C#EF6编码第一个EntityState



我有一个使用EF6更新数据的C#web。并且在更新期间将触发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列)

表3rowId用于t3(表中有9列)

我找不到他们返回这些列的原因。

注:两个表都包含列createdAt, createdBy, updatedAt, updatedBy

为了解决这个问题,我试图从代码中删除这些语句

dbdb.Entry(t1).State = EntityState.Modified;  
dbdb.Entry(t2).State = EntityState.Modified;  
dbdb.Entry(t3).State = EntityState.Modified;  

因此,我认为问题是在db.SaveChange()之前附加EntityState

我想知道

  1. 为什么附加EntityState会导致数据表中出现那些意外的更新列?

  2. 什么时候我应该附加EntityState.Modified(我认为像上面的代码一样在更新记录时这样做是合适的,但很明显触发器显示它不是)?

----------------已更新-----------------删除EntityState之后。根据代码修改。触发器仍然无法接收正确的@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时,可以重现相同的结果(在触发器中找不到UPDATED COLUMN)。

因此,我认为SQL Server更新触发器、仅获取修改过的字段只能用于以前版本的SQL Server。

至少我的数据库(SQLSERVER 2014(120))无法将标记的答案应用于查找更新的列。

最后,我应用了另一个透视已删除和插入的表并找到不同的表的方法,没有理由再失败了,除非它需要表中一个未更改的列(幸运的是,我所有的表都有应该未更改的主键)。

唯一的问题是维护每个表修改的触发器。

谢谢。

来自MSDN:

当您将状态更改为Modified时,实体的所有属性都将标记为Modified,并且在调用SaveChanges时,所有属性值都将发送到数据库。

从数据库中检索实体对象时,EF会为您跟踪实体对象的状态。这意味着更改任何属性值并使用SaveChanges保存实体也将保留您的更改,并且您不需要将实体状态显式标记为EntityState.Modified

希望这能有所帮助。

第页。S.如果你对审计有要求,你可以看看EntityFramework Plus审计。我建议,因为我们正在工作中使用它,我与"EntityFramework Plus"没有任何关系。

最新更新