如何从DbContext.Attach()获取原始值?

时间:2014-04-03 09:12:40

标签: .net entity-framework entity-framework-5

我正在使用在.NET 4.5上运行的EntityFramework 5

我正尝试使用以下方法执行记录更新:

var rec = DbCntx.MyRecords.Attach(changedRecord);
var entry = DbCntx.Entry(changedRecord);
if (entry.State == EntityState.Modified) DbCntx.SaveChanges();

传入的数据对象changedRecord包含至少1个已修改的字段值,与实际的db进行比较。 但是,Entry.State始终不变,因此SaveChanges()永远不会触发。

我正在编写此更新例程以支持对changedRecord的任何数据更改,数据更改完全取决于客户端/调用方,因此我不应该专门更改此例程中的任何字段值。 / p>

我使用这种方法的问题是,我无法获得原始数据值。我可以访问的所有实体都与changedRecord完全相同,后者是一个断开连接的记录,其中包含我尚未提交到db中的更改。

如果没有原始数据,我无法确定哪些属性发生了变化。 如果我尝试使用Find(),First / SingleOrDefault()来定位记录1st,我以后不能使用Attach(),因为它会导致错误" ObjectStateManager无法跟踪具有相同键的多个对象&#34 34。

来自Googling的

,有人暗示使用Detach(),但DbContext中没有Detach。

2 个答案:

答案 0 :(得分:0)

通常情况下,您希望使用AddOrUpdate(或this版本6):

using System.Data.Entity.Migrations;
....

DbCntx.MyRecords.AddOrUpdate(changedRecord);
DbCntx.SaveChanges();

这会将所有已更改的属性标记为已修改。默认情况下,实体是通过其键值从数据库中获取的。如有必要,您可以告诉AddOrUpdate使用备用密钥。

答案 1 :(得分:0)

Gert提出的AddOrUpdate()确实奏效了。 但是,我需要捕捉代码中的差异。最后,这是我使用DbPropertyValues编写的:

            dbCntx.MyRec.Attach(chgRec);

            var entry = dbCntx.Entry(chgRec);

            var dbVals = entry.GetDatabaseValues();
            var dbValsPs = dbVals.PropertyNames;

            foreach (var p in dbValsPs)
            {
                var ep = entry.Property(p);
                var cv = ep.CurrentValue;
                var dbv = dbVals.GetValue<object>(p);

                if (!MyHelper.AreValuesEqual(cv, dbv))
                    ep.IsModified = true;
            }

            if (entry.State == EntityState.Modified)
                affectedCount = dbCntx.SaveChanges();

    public static bool AreValuesEqual<T>(T valueA, T valueB)
    {
        // array handling (such as byte[])
        if (valueA != null)
        {
            if (valueB == null) return false;

            Type t = valueA.GetType();
            if (t.IsArray)
            {
                IEnumerable<object> listA = (valueA as Array).Cast<object>();
                IEnumerable<object> listB = (valueB as Array).Cast<object>();
                return listA.SequenceEqual(listB);
            }
        }

        return EqualityComparer<T>.Default.Equals(valueA, valueB);