【问题标题】:Setting WHERE condition to use Ids.Contains() in ExecuteSqlCommand()在 ExecuteSqlCommand() 中设置 WHERE 条件以使用 Ids.Contains()
【发布时间】:2017-05-14 23:08:46
【问题描述】:

我正在使用实体框架,我想执行批量更新。加载每一行,更新这些行,然后将它们保存回数据库,效率太低了。

所以我更喜欢使用DbContext.Database.ExecuteSqlCommand()。但是如何使用此方法更新所有这些行,其中包含我的 ID 列表中包含的 ID?

这是我目前所拥有的。

IEnumerable<int> Ids;
DbContext.Database.ExecuteSqlCommand("UPDATE Messages SET Viewed = 1 WHERE Id IN (@list)", Ids);

我意识到我可以使用正确的查询手动构建一个字符串,但我更愿意按照通常的建议传递我的参数。

有什么办法可以做到吗?

【问题讨论】:

  • 我建议研究一下表值参数的工作原理(尽管 TVP 用于存储过程,而不是书面命令)。应该有很多关于这个的问题。例如here。除此之外,我认为您必须将列表作为字符串传递并以某种方式将其拆分(例如字符串拆分函数)或使用 LIKE 语句。还有很多关于这个的问题,所以应该很容易找到满足你要求的东西。
  • @ZLK:谢谢,但我真的不确定如何在这里使用表值参数。
  • 我链接的问题有一个简短示例的链接,说明您如何实现这一目标:codeproject.com/Articles/22392/…(我不相信有一种方法可以使用简单的 executesqlcommand 语句来实现,但我可能是错的)。本质上,您需要创建一个表类型(带有一个 INT 列),创建一个以该类型的 TVP 作为参数的存储过程,然后通过传递一个包含您的值的数据表来执行存储过程。
  • 现在运行代码会出现什么错误?您没有指定(尽管我可以推测它为什么会失败,因为在 DbParameter 中的 DbTypes 之一中可能没有 List 或 IEnumerable 的序列化程序)
  • @MarkC.:说实话,我什至没有运行它。 500.00 美元表示它无法按照我的意愿进行解析。好吧,我刚试过。它似乎没有引发异常,但似乎也没有做任何事情。

标签: c# sql-server entity-framework dbcontext


【解决方案1】:

您仍然可以构建参数并将它们包含在参数化查询中。

查询在生成时看起来像这样

UPDATE Messages SET Viewed = 1 WHERE Id IN (@p0, @p1, @p2, ..., @pn)

所以给定

IEnumerable<int> Ids;

然后

var parameters = Ids.Select((id, index) => new SqlParameter(string.Format("@p{0}", index), id));
var parameterNames = string.Join(", ", parameters.Select(p => p.ParameterName));
var query = string.Format("UPDATE Messages SET Viewed = 1 WHERE Id IN ({0})", parameterNames);

int affected = DbContext.Database.ExecuteSqlCommand(query, parameters.ToArray());

【讨论】:

  • 我认为这是一个很好的答案,但不是 OP 想要的答案。
  • 有趣的建议。 ExecuteSqlCommand 可能是您能做的最好的事情。
  • 这就是我目前使用 EF 的方式。我已经搜索了你很长时间的请求。当我在一些 MS 文档中看到它时,我决定采用这种格式。
  • @Nkosi:显然,有一点需要付出更多的努力,而实际上效率并不高。但看起来这仍然会更有效率。
  • @Nkosi:到目前为止,我收到了一个异常System.ArgumentException: 'No mapping exists from object type System.Int32[] to a known managed provider native type.'。你试过代码了吗?
【解决方案2】:

您可以生成包含尽可能多的参数的查询字符串,而不是生成具有精确值的查询字符串。 所以你会得到这样的:

DbContext.Database.ExecuteSqlCommand("UPDATE Messages SET Viewed = 1 WHERE Id IN (@p0,@p1,@p2,...,@pN)", Ids);

这样的:

var paramsDef = string.Concat(Ids.Select(x=>$"{(Ids.IndexOf(x) > 0 ? "," : "")}p{Ids.IndexOf(x)}"));            
DbContext.Database.ExecuteSqlCommand($"UPDATE Messages SET Viewed = 1 WHERE Id IN {paramsDef}", Ids);

我发现有人用 SqlCommand 做类似的一些链接: http://www.svenbit.com/2014/08/using-sqlparameter-with-sqls-in-clause-in-csharp/ http://nodogmablog.bryanhogan.net/2016/01/parameterize-sql-where-in-clause-c/

【讨论】:

    猜你喜欢
    • 2021-12-29
    • 2022-10-23
    • 2018-01-12
    • 2010-11-29
    • 2018-11-29
    • 2022-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多