我有一个使用EF6更新数据的C#网页。并且在更新期间将触发SQL Server触发器。触发器应该通过
找到更新的列SELECT
@Columns_Updated = ISNULL(@Columns_Updated + ',', '') + name
FROM
syscolumns
WHERE
id = @idTable
AND CONVERT(VARBINARY, REVERSE(COLUMNS_UPDATED())) & POWER(CONVERT(BIGINT, 2), colorder - 1) > 0
我在下面的陈述中有一个问题
CrmClientContact t1 = dbdb.CrmClientContact.Where(x => x.rowId == 4).FirstOrDefault();
t1.updatedAt = DateTime.Now;
dbdb.Entry(t1).State = EntityState.Modified;
dbdb.SaveChanges();
CrmClientBetLimit t2 = dbdb.CrmClientBetLimit.Where(x => x.rowId == 1028).FirstOrDefault();
t2.updatedAt = DateTime.Now;
dbdb.Entry(t2).State = EntityState.Modified;
dbdb.SaveChanges();
CrmClientCLState t3 = dbdb.CrmClientCLState.Where(x => x.rowId==1).FirstOrDefault();
t3.updatedAt = DateTime.Now;
dbdb.Entry(t3).State = EntityState.Modified;
dbdb.SaveChanges();
这是我通常用来更新EF6框架中的记录。
如图所示,我更新了这3个表中的字段updatedAt
。
然而,触发器显示完全不同的@Columns_Updated
表1:t1的 clientId,createdAt,createdBy,name,rowId (表中有11列)
表2:t2的 betLimitValueSum,clientId,createdAt,createdBy,currId,updatedAt,updatedBy (表中有8列)
表3. t3的 rowId (表中有9列)
我找不到他们返回这些列的原因。
注意:两个表都包含createdAt, createdBy, updatedAt, updatedBy
列
为了解决这个问题,我尝试从代码中删除这些语句
dbdb.Entry(t1).State = EntityState.Modified;
dbdb.Entry(t2).State = EntityState.Modified;
dbdb.Entry(t3).State = EntityState.Modified;
因此,我认为问题是在EntityState
之前附加db.SaveChange()
。
我想知道
为什么附加EntityState
会导致这些意外更新列出现在数据表中?
当我应该附加EntityState.Modified
时(我认为在更新上述代码的记录时这样做是正确的,但显然触发器显示不是这样)?
-----------------更新----------------- 从代码中删除EntityState.Modified后。触发器仍然无法接收正确的@UpdatedColumns,我尝试了下面的代码
t3 = dbdb.CrmClientContact.Where(x => x.rowId == 7).FirstOrDefault();
t3.updatedAt = DateTime.Now;
t3.updatedBy = DateTime.Now.ToString();
t3.mobile = DateTime.Now.ToString();
t3.name = DateTime.Now.ToString();
dbdb.SaveChanges();
但是,在触发器中,它将 createdAt,rowId 作为更新的列返回。请注意,有些表可以正常工作。
我的行为意外完成。例如
CrmClientContact t3 = dbdb.CrmClientContact.Where(x => x.rowId == 5).FirstOrDefault();
t3.updatedAt = DateTime.Now;
t3.email = DateTime.Now.ToString();
dbdb.SaveChanges(); // correct
t3 = dbdb.CrmClientContact.Where(x => x.rowId == 5).FirstOrDefault();
t3.updatedAt = DateTime.Now.AddDays(1);
t3.email = DateTime.Now.ToString() + 1;
dbdb.SaveChanges(); //correct
t3 = dbdb.CrmClientContact.Where(x => x.rowId == 5).FirstOrDefault();
t3.updatedAt = DateTime.Now.AddDays(2);
t3.email = DateTime.Now.ToString() + 2;
t3.mobile = DateTime.Now.ToString() + 2;
t3.name = DateTime.Now.ToString() + 2;
dbdb.SaveChanges(); // correct
t3 = dbdb.CrmClientContact.Where(x => x.rowId == 5).FirstOrDefault();
t3.updatedAt = DateTime.Now;
t3.updatedBy = DateTime.Now.ToString();
dbdb.SaveChanges(); // correct
t3 = dbdb.CrmClientContact.Where(x => x.rowId == 5).FirstOrDefault();
t3.updatedAt = DateTime.Now.AddDays(1);
t3.updatedBy = DateTime.Now.ToString()+1;
dbdb.SaveChanges(); // correct
t3 = dbdb.CrmClientContact.Where(x => x.rowId == 5).FirstOrDefault();
t3.updatedAt = DateTime.Now.AddDays(2);
t3.updatedBy = DateTime.Now.ToString() + 2;
dbdb.SaveChanges(); // correct
t3 = dbdb.CrmClientContact.Where(x => x.rowId == 5).FirstOrDefault();
t3.updatedBy =3+ DateTime.Now.ToString();
t3.email =1+ DateTime.Now.ToString();
dbdb.SaveChanges();//null, incorrect
t3 = dbdb.CrmClientContact.Where(x => x.rowId == 5).FirstOrDefault();
t3.updatedBy =2+ DateTime.Now.ToString();
t3.email =1+ DateTime.Now.ToString();
dbdb.SaveChanges();//updatedBy, incorrect (email is missing)
t3 = dbdb.CrmClientContact.Where(x => x.rowId == 5).FirstOrDefault();
t3.updatedBy = 22 + DateTime.Now.ToString();
t3.email = 11 + DateTime.Now.ToString();
dbdb.SaveChanges();//null, incorrect
t3 = dbdb.CrmClientContact.Where(x => x.rowId == 5).FirstOrDefault();
t3.updatedBy = 222 + DateTime.Now.ToString();
t3.email = 111 + DateTime.Now.ToString();
dbdb.SaveChanges();//null, incorrect
t3 = dbdb.CrmClientContact.Where(x => x.rowId == 5).FirstOrDefault();
t3.updatedBy = 22 + DateTime.Now.ToString();
t3.email = 11 + DateTime.Now.ToString();
dbdb.SaveChanges();//null, incorrect
CrmClientContact t4 = dbdb.CrmClientContact.Where(x => x.rowId == 5).FirstOrDefault();
t4.updatedBy = 2 + DateTime.Now.ToString();
t4.email = 1 + DateTime.Now.ToString();
dbdb.SaveChanges();//null, incorrect
如上所示,我完全不明白上述结果集是如何发生的(它们是确定性的,可重复的)
--------------最后更新-------------- 使用SQL分析器后,我发现EF6的SQL查询只是一个与文档匹配的普通更新语句。在管理工作室中执行相同的SQL时,可以重现相同的结果(在触发器中找不到更新的列)。
结果,我认为SQL Server Update Trigger, Get Only modified fields只适用于以前版本的SQL服务器。
至少我的数据库(SQLSERVER 2014(120))无法应用标记的答案来查找更新的列。
最后我应用了另一个转动已删除和插入的表并查找不同的表,除了它需要表中未更改的列之外没有理由再失败(幸运的是我的所有表都有主键,应该保持不变) 。
唯一的问题是维护每个表修改的触发器。
感谢。
答案 0 :(得分:0)
来自MSDN:
当您将状态更改为Modified时,实体的所有属性都将被标记为已修改,并且在调用SaveChanges时,所有属性值都将发送到数据库。
从数据库中检索实体对象时,EF会为您跟踪实体对象的状态。这意味着更改任何属性值并使用SaveChanges
保存实体也会保留您的更改,并且您无需将实体状态明确标记为EntityState.Modified
。
希望这有帮助。
P.S。如果您有审核要求,可以查看EntityFramework-Plus Audit。我建议,因为我们在工作中使用它,而且我与“EntityFramework-Plus”没有任何关系。