DbContext.Database.ExecuteSqlCommand 메서드에 매개 변수를 전달하는 방법은 무엇입니까?
Entity Framework에서 sql 명령을 직접 실행할 필요가 있다고 가정 해 봅시다. 내 SQL 문에서 매개 변수를 사용하는 방법을 알아내는 데 문제가 있습니다. 다음 예제 (실제 예제는 아님)가 작동하지 않습니다.
var firstName = "John";
var id = 12;
var sql = @"Update [User] SET FirstName = @FirstName WHERE Id = @Id";
ctx.Database.ExecuteSqlCommand(sql, firstName, id);
ExecuteSqlCommand 메서드를 사용하면 ADO.Net에서와 같이 명명 된 매개 변수를 전달할 수 없으며이 메서드에 대한 설명서 에는 매개 변수가있는 쿼리를 실행하는 방법에 대한 예가 없습니다.
매개 변수를 올바르게 지정하려면 어떻게합니까?
이 시도:
var sql = @"Update [User] SET FirstName = @FirstName WHERE Id = @Id";
ctx.Database.ExecuteSqlCommand(
sql,
new SqlParameter("@FirstName", firstname),
new SqlParameter("@Id", id));
이것이 작동한다는 것이 밝혀졌습니다.
var firstName = "John";
var id = 12;
var sql = "Update [User] SET FirstName = {0} WHERE Id = {1}";
ctx.Database.ExecuteSqlCommand(sql, firstName, id);
다음 중 하나를 수행 할 수 있습니다.
1) 원시 인수를 전달하고 {0} 구문을 사용하십시오. 예 :
DbContext.Database.SqlQuery("StoredProcedureName {0}", paramName);
2) DbParameter 서브 클래스 인수를 전달하고 @ParamName 구문을 사용하십시오.
DbContext.Database.SqlQuery("StoredProcedureName @ParamName",
new SqlParameter("@ParamName", paramValue);
첫 번째 구문을 사용하는 경우 EF는 실제로 인수를 DbParamater 클래스로 랩핑하고 이름을 지정하고 {0}을 생성 된 매개 변수 이름으로 바꿉니다.
팩토리를 사용하거나 작성할 DbParamater 유형 (SqlParameter, OracleParamter 등)을 알 필요가 없기 때문에 선호하는 경우 첫 번째 구문입니다.
Oracle을 사용할 때는 다른 답변이 작동하지 않습니다. :
대신 사용해야 합니다 @
.
var sql = "Update [User] SET FirstName = :FirstName WHERE Id = :Id";
context.Database.ExecuteSqlCommand(
sql,
new OracleParameter(":FirstName", firstName),
new OracleParameter(":Id", id));
이것을 시도하십시오 (편집 됨).
ctx.Database.ExecuteSqlCommand(sql, new SqlParameter("FirstName", firstName),
new SqlParameter("Id", id));
이전 아이디어가 잘못되었습니다.
entity Framework Core 2.0 이상에서이를 수행하는 올바른 방법은 다음과 같습니다.
var firstName = "John";
var id = 12;
ctx.Database.ExecuteSqlCommand($"Update [User] SET FirstName = {firstName} WHERE Id = {id}";
Entity Framework는 두 개의 매개 변수를 생성하므로 Sql Injection으로부터 보호됩니다.
또한 다음이 아닙니다.
var firstName = "John";
var id = 12;
var sql = $"Update [User] SET FirstName = {firstName} WHERE Id = {id}";
ctx.Database.ExecuteSqlCommand(sql);
Sql Injection으로부터 사용자를 보호하지 않으며 매개 변수가 생성되지 않기 때문입니다.
자세한 내용은 이것을 참조하십시오 .
Simplified version for Oracle. If you don't want to create OracleParameter
var sql = "Update [User] SET FirstName = :p0 WHERE Id = :p1";
context.Database.ExecuteSqlCommand(sql, firstName, id);
var firstName = "John";
var id = 12;
ctx.Database.ExecuteSqlCommand(@"Update [User] SET FirstName = {0} WHERE Id = {1}"
, new object[]{ firstName, id });
This is so simple !!!
Image for knowing parameter reference
For the async Method ("ExecuteSqlCommandAsync") you can use it like this:
var sql = @"Update [User] SET FirstName = @FirstName WHERE Id = @Id";
await ctx.Database.ExecuteSqlCommandAsync(
sql,
parameters: new[]{
new SqlParameter("@FirstName", firstname),
new SqlParameter("@Id", id)
});
public static class DbEx {
public static IEnumerable<T> SqlQueryPrm<T>(this System.Data.Entity.Database database, string sql, object parameters) {
using (var tmp_cmd = database.Connection.CreateCommand()) {
var dict = ToDictionary(parameters);
int i = 0;
var arr = new object[dict.Count];
foreach (var one_kvp in dict) {
var param = tmp_cmd.CreateParameter();
param.ParameterName = one_kvp.Key;
if (one_kvp.Value == null) {
param.Value = DBNull.Value;
} else {
param.Value = one_kvp.Value;
}
arr[i] = param;
i++;
}
return database.SqlQuery<T>(sql, arr);
}
}
private static IDictionary<string, object> ToDictionary(object data) {
var attr = System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance;
var dict = new Dictionary<string, object>();
foreach (var property in data.GetType().GetProperties(attr)) {
if (property.CanRead) {
dict.Add(property.Name, property.GetValue(data, null));
}
}
return dict;
}
}
Usage:
var names = db.Database.SqlQueryPrm<string>("select name from position_category where id_key=@id_key", new { id_key = "mgr" }).ToList();
If your underlying database data types are varchar then you should stick with the approach below. Otherwise the query would have a huge performance impact.
var firstName = new SqlParameter("@firstName", System.Data.SqlDbType.VarChar, 20)
{
Value = "whatever"
};
var id = new SqlParameter("@id", System.Data.SqlDbType.Int)
{
Value = 1
};
ctx.Database.ExecuteSqlCommand(@"Update [User] SET FirstName = @firstName WHERE Id = @id"
, firstName, id);
You can check Sql profiler to see the difference.
Multiple params in a stored procedure that has multiple params in vb:
Dim result= db.Database.ExecuteSqlCommand("StoredProcedureName @a,@b,@c,@d,@e", a, b, c, d, e)
Stored procedures can be executed like below
string cmd = Constants.StoredProcs.usp_AddRoles.ToString() + " @userId, @roleIdList";
int result = db.Database
.ExecuteSqlCommand
(
cmd,
new SqlParameter("@userId", userId),
new SqlParameter("@roleIdList", roleId)
);
For .NET Core 2.2, you can use FormattableString
for dynamic SQL.
//Assuming this is your dynamic value and this not coming from user input
var tableName = "LogTable";
// let's say target date is coming from user input
var targetDate = DateTime.Now.Date.AddDays(-30);
var param = new SqlParameter("@targetDate", targetDate);
var sql = string.Format("Delete From {0} Where CreatedDate < @targetDate", tableName);
var froamttedSql = FormattableStringFactory.Create(sql, param);
_db.Database.ExecuteSqlCommand(froamttedSql);
'IT story' 카테고리의 다른 글
Angular 2의 URL에서 쿼리 매개 변수를 얻는 방법은 무엇입니까? (0) | 2020.04.30 |
---|---|
SQL Server에서 올바른 트랜잭션 사용 (0) | 2020.04.30 |
지정된 응용 프로그램 암호화 키가 없습니다 (0) | 2020.04.30 |
Vim에서 분할 창 취소 (0) | 2020.04.30 |
Django에서 날짜 범위별로 쿼리 객체를 어떻게 필터링합니까? (0) | 2020.04.30 |