C#EF6代码优先实体状态

时间:2017-01-03 04:45:00

标签: sql-server entity-framework

我有一个使用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()

我想知道

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

  2. 当我应该附加EntityState.Modified时(我认为在更新上述代码的记录时这样做是正确的,但显然触发器显示不是这样)?

  3. -----------------更新----------------- 从代码中删除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))无法应用标记的答案来查找更新的列。

    最后我应用了另一个转动已删除和插入的表并查找不同的表,除了它需要表中未更改的列之外没有理由再失败(幸运的是我的所有表都有主键,应该保持不变) 。

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

    感谢。

1 个答案:

答案 0 :(得分:0)

来自MSDN

  

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

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

希望这有帮助。

P.S。如果您有审核要求,可以查看EntityFramework-Plus Audit。我建议,因为我们在工作中使用它,而且我与“EntityFramework-Plus”没有任何关系。