Ответ 1
Оказывается, что это работает.
var firstName = "John";
var id = 12;
var sql = "Update [User] SET FirstName = {0} WHERE Id = {1}";
ctx.Database.ExecuteSqlCommand(sql, firstName, id);
Предположим, что у меня есть действительная потребность в непосредственном выполнении команды sql в Entity Framework. Мне трудно понять, как использовать параметры в моей инструкции 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 firstName = "John";
var id = 12;
var sql = "Update [User] SET FirstName = {0} WHERE Id = {1}";
ctx.Database.ExecuteSqlCommand(sql, firstName, id);
Попробуйте следующее:
var sql = @"Update [User] SET FirstName = @FirstName WHERE Id = @Id";
ctx.Database.ExecuteSqlCommand(
sql,
new SqlParameter("@FirstName", firstname),
new SqlParameter("@Id", id));
Вы также можете:
1) Передайте исходные аргументы и используйте синтаксис {0}. Например:
DbContext.Database.SqlQuery("StoredProcedureName {0}", paramName);
2) Пропустите аргументы подкласса DbParameter и используйте синтаксис @ParamName.
DbContext.Database.SqlQuery("StoredProcedureName @ParamName",
new SqlParameter("@ParamName", paramValue);
Если вы используете первый синтаксис, EF фактически перенесет ваши аргументы в классы DbParamater, назначит им имена и заменит {0} на сгенерированное имя параметра.
Первый синтаксис, если это необходимо, потому что вам не нужно использовать фабрику или знать, какой тип создаваемых DbParamaters (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.
Также обратите внимание, что это НЕ:
var firstName = "John";
var id = 12;
var sql = $"Update [User] SET FirstName = {firstName} WHERE Id = {id}";
ctx.Database.ExecuteSqlCommand(sql);
потому что это НЕ защищает вас от Sql Injection, и параметры не создаются.
Смотрите это для получения дополнительной информации.
Упрощенная версия для Oracle. Если вы не хотите создавать 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 });
Это так просто !!!
Изображение для указания параметра
Для асинхронного метода ( "ExecuteSqlCommandAsync" ) вы можете использовать его следующим образом:
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;
}
}
Использование:
var names = db.Database.SqlQueryPrm<string>("select name from position_category where [email protected]_key", new { id_key = "mgr" }).ToList();
Если ваши базовые типы данных базы данных являются varchar, тогда вы должны придерживаться подхода ниже. В противном случае запрос будет иметь огромное влияние на производительность.
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);
Вы можете проверить профилировщик Sql, чтобы увидеть разницу.
Несколько параметров в хранимой процедуре с несколькими параметрами в vb:
Dim result= db.Database.ExecuteSqlCommand("StoredProcedureName @a,@b,@c,@d,@e", a, b, c, d, e)
Хранимые процедуры могут быть выполнены, как показано ниже
string cmd = Constants.StoredProcs.usp_AddRoles.ToString() + " @userId, @roleIdList";
int result = db.Database
.ExecuteSqlCommand
(
cmd,
new SqlParameter("@userId", userId),
new SqlParameter("@roleIdList", roleId)
);
Для .NET Core 2.2 вы можете использовать FormattableString
для динамического SQL.
//Assuming this is your dynamic value and this not coming from user input
var tableName = "LogTable";
// let 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);