我正在使用在.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。
答案 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);