使用 linq 生成直接更新,无需选择
Posted
技术标签:
【中文标题】使用 linq 生成直接更新,无需选择【英文标题】:Use linq to generate direct update without select 【发布时间】:2010-10-01 11:54:36 【问题描述】:祝大家生日快乐。
我还在学习 LINQ,如果这很幼稚,请原谅我。当您直接处理 SQL 时,您可以生成带有条件的更新命令,而无需运行 select 语句。
当我使用 linq 时,我似乎遵循以下模式:
-
选择实体
修改实体
提交更改
我想要做的是使用 linq 和延迟执行的直接更新。是否有可能直接在 SQL 上执行实际执行,而无需将任何数据传输到客户端?
DataContext dc = new DataContext
var q = from product in dc.Products
where product.Type = 1
set product.Count = 0
dc.SubmitChanges
所以本质上 LINQ 拥有它需要的所有信息,而无需使用 select 来生成更新命令。它将运行 SQL:
Update Products Set Count = 0 Where Type = 1
LINQ 中是否存在类似“set”的关键字?
【问题讨论】:
当前接受的答案是错误的——你能选择正确的吗? 下面的答案不允许我描述的基于集合的更新,但它们很有趣。 【参考方案1】:您实际上可以让 LINQ-to-SQL 生成更新语句:
Foo foo=new Foo FooId=fooId ; // create obj and set keys
context.Foos.Attach(foo);
foo.Name="test";
context.SubmitChanges();
在您的 Dbml 中为所有属性设置 UpdateCheck="Never"。
这将生成一个更新语句,而无需先进行选择。
一个警告:如果您希望能够将 Name 设置为 null,则必须将 foo 对象初始化为不同的值,以便 Linq 可以检测到更改:
Foo foo=new Foo FooId=fooId, Name="###" ;
...
foo.Name=null;
如果您想在更新时检查时间戳,您也可以这样做:
Foo foo=new Foo FooId=fooId, Modified=... ;
// Modified needs to be set to UpdateCheck="Always" in the dbml
【讨论】:
虽然它不是完全基于集合。虽然知道附加语法很酷 另一种方法是:context.Foos.Attach(foo, original: new Foo FooId = fooId );
。这将更新原始实体中未设置的所有属性。【参考方案2】:
不,LINQ 和 LINQ to SQL 都没有基于集合的更新功能。
在 LINQ to SQL 中,您必须查询要更新的对象,根据需要更新字段/属性,然后调用 SubmitChanges()。例如:
var qry = from product in dc.Products where Product.Name=='Foobar' select product;
var item = qry.Single();
item.Count = 0;
dc.SubmitChanges();
如果您想进行批处理:
var qry = from product in dc.Products where Product.Type==1 select product;
foreach(var item in qry)
item.Count = 0;
dc.SubmitChanges();
或者,您可以自己编写查询:
dc.ExecuteCommand("update Product set Count=0 where Type=1", null);
【讨论】:
这是我的代码,我想知道 LINQ 是否有它的语法。不过为答案喝彩,在 C# 中进行更新确实很有意义,因为我想如果你想编写 SQL,你应该像执行命令函数那样编写 sql。 这真是太傻了,linq to sql应该有更新字段 @PeterRuderman 下面的附加答案需要知道 fooId。很少有场景(尤其是我的场景)不想知道此信息,只需将更新转换为 SQL。如果您对要更新的主键有一些其他知识,则以下内容很有用。此外,这只会更新一行,而不是整个表,并且不会获得基于集合的性能提升。【参考方案3】:PLINQO (http://plinqo.com) 框架正在使用 LINQ 批量更新来执行更新
context.Task.Update(t => t.Id == 1, t2 => new Task StatusId = 2);
这将执行Update Task Set StatusId = 2 Where Id = 1
【讨论】:
【参考方案4】:Linq 2 SQL 没有直接插入/更新/删除等价的 SQL。在 V1 中,您可以使用 linq 进行的唯一更新被认为是上下文中的 SubmmitChanges,或者如果您回退到 sql。
然而,有些人尝试使用自定义实现来克服 linq 的这一限制。
Linq batch update.
【讨论】:
干杯伙伴,这是一个非常有趣的阅读。让我们希望其中的一些能够进入 C# 4 或 5,因为批量更新和删除的能力是 LINQ 中唯一真正缺少的东西。【参考方案5】:使用此扩展方法:EntityExtensionMethods.cs
public static void UpdateOnSubmit<TEntity>(this Table<TEntity> table, TEntity entity, TEntity original = null)
where TEntity : class, new()
if (original == null)
// Create original object with only primary keys set
original = new TEntity();
var entityType = typeof(TEntity);
var dataMembers = table.Context.Mapping.GetMetaType(entityType).DataMembers;
foreach (var member in dataMembers.Where(m => m.IsPrimaryKey))
var propValue = entityType.GetProperty(member.Name).GetValue(entity, null);
entityType.InvokeMember(member.Name, BindingFlags.SetProperty, Type.DefaultBinder,
original, new[] propValue );
// This will update all columns that are not set in 'original' object. For
// this to work, entity has to have UpdateCheck=Never for all properties except
// for primary keys. This will update the record without querying it first.
table.Attach(entity, original);
要使用它,请确保您传递给UpdateOnSubmit
方法的entity
对象具有为您要更新的记录设置的所有主键属性。然后,此方法将使用 entity
对象中的剩余属性更新记录,而无需先提取记录。
致电UpdateOnSubmit
后,请务必致电SubmitChanges()
以应用更改。
【讨论】:
感谢奥拉德。这与 laktak 的回答一致,但仍然存在同样的问题,即它实际上是在推断单行和表的知识。我的问题是 LINQ 是否最终会向 SQL 发出基于集合的更新查询,而它不会开箱即用。 嗨@Spence,我不认为可以通过LINQ 批量更新set
,您可以使用AttachAll
方法,但我认为它仍会为每一行执行单独的更新命令。我的解决方案没有像问题标题中那样选择直接更新,但如果您的具体问题是如何进行批量更新,则接受的答案是正确的。【参考方案6】:
您可以使用Entity Framework Extensions库,它支持批量更新和批量合并,但是该库不是免费的:
PM > 安装包 Z.EntityFramework.Extensions
using Z.EntityFramework.Plus;
...
dc.Products
.Where(q => q.Type == 1)
.Update(q => new Product Count = 0 );
【讨论】:
【参考方案7】:试试这个:
dbEntities.tblSearchItems
.Where(t => t.SearchItemId == SearchItemId)
.ToList()
.ForEach(t => t.isNew = false);
dbEntities.SaveChanges();
【讨论】:
阿米特,对“ToList”的调用会将数据库中的所有项目加载到内存中。 foreach 在内存中工作,然后 savechanges 将它们传播回来。我正在寻找一些会产生 SQL 语句“更新条件条件”的东西,它不会在本地加载任何数据。以上是关于使用 linq 生成直接更新,无需选择的主要内容,如果未能解决你的问题,请参考以下文章
Linq to entity 使用“Func”在生成匿名对象的选择语句中创建属性