【发布时间】:2011-12-29 08:34:35
【问题描述】:
在 EF 4.0 中,如果我理解正确的话,Entity 中有两种类型的值:当前值和原始值。
我们可以通过调用 ApplyOriginalValues(TEntity) 方法来设置原始值,但是如何获取原始值呢?
【问题讨论】:
在 EF 4.0 中,如果我理解正确的话,Entity 中有两种类型的值:当前值和原始值。
我们可以通过调用 ApplyOriginalValues(TEntity) 方法来设置原始值,但是如何获取原始值呢?
【问题讨论】:
@Eranga 的答案对于 EF 5 已过时。出于某种原因,EF 5 在使用如下语句获取原始值时无法正常工作:
var originalValues = context.Entry(myEntity).OriginalValues;
我的工作解决方案使用来自DbSet 的AsNoTracking() 方法,如下例所示:
var originalEntity = context.MyEntities.AsNoTracking().FirstOrDefault(me => me.MyEntityID == myEntity.MyEntityID);
【讨论】:
您可以通过ObjectStateEntry访问它们
var originalValues = context
.ObjectStateManager.GetObjectStateEntry(myEntity).OriginalValues;
【讨论】:
var name = (string)originalValues["Name"];
这可以进一步细化为:
var originalEntity = context.MyEntities.AsNoTracking()
.FirstOrDefault(me => me.MyEntityID == myEntity.MyEntityID);
上面的Where,很好,不需要回复。
【讨论】:
var originalEntity = (EntityType)context.Entry(editEntity).OriginalValues.ToObject();
对不起我的英语。 通过这种方式,您可以在不更改编辑值的情况下以对象实体的形式获取原始实体值。
示例: 如果你喜欢编辑一个人,顶部的行看起来像这样
var originalPerson = (Person)context.Entry(editPerson).OriginalValues.ToObject();
【讨论】:
我遇到了类似的问题,AsNoTracking 不是我的情况的选择,所以我想出了一些对我来说足够好的方法:首先“克隆”实体然后进行更改。
public T Clone<T>(T entity)
where T : class, new() {
var clone = new T();
var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy)
.Where(a => a.CanRead &&
a.CanWrite &&
a.GetMethod.IsFinal);
foreach (var property in properties) {
property.SetValue(clone, property.GetValue(entity));
}
return clone;
}
然后将克隆与更改进行比较。
public string GenerateChangeText<T>(T original, T current)
where T : class, new() {
var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy)
.Where(a => a.CanRead &&
a.CanWrite &&
a.GetMethod.IsFinal);
var changes = string.Empty;
foreach (var property in properties) {
var originalValue = property.GetValue(original);
var currentValue = property.GetValue(current);
if (originalValue == null && currentValue == null) continue;
if ((originalValue != null && !originalValue.Equals(currentValue)) ||
(currentValue != null && !currentValue.Equals(originalValue))) {
changes += $" changed {property} from {original ?? "NULL"} to {current ?? "NULL"}.";
}
}
return changes;
}
【讨论】:
有几个版本的实体框架在使用中。
我自己更喜欢 Code First 并且使用该 API 很简单
_context.Entry(Entity).Reload();
较旧的 API 在 ObjectContext 上有一个 Refresh 方法,可以在某些用例中提供帮助
ObjectContext.Refresh(RefreshMode.StoreWins, Entity);
文档https://msdn.microsoft.com/en-us/library/bb896255(v=vs.110).aspx
【讨论】:
这个答案是指实体框架 6。在 EF 6 中有一个原始值和当前值https://msdn.microsoft.com/en-us/library/gg679512(v=vs.113).aspx 在寻找并没有找到一个好的答案之后,我想出了以下测试函数,并认为我会将它发布给其他需要的人做同样的事情。
private void test()
{
// table has a field Description of type varchar(200)
WDMDBEntities context = new WDMDBEntities();
var query = context.Brands;
List<Brand> records = query.ToList();
if (records.Count > 0)
{
Brand currentRecord = records[0];
currentRecord.Description = "some new text";
string originalValue = null;
switch (context.Entry(currentRecord).State)
{
case System.Data.Entity.EntityState.Added:
originalValue = null;
break;
case System.Data.Entity.EntityState.Deleted:
case System.Data.Entity.EntityState.Detached:
case System.Data.Entity.EntityState.Modified:
case System.Data.Entity.EntityState.Unchanged:
originalValue = context.Entry(currentRecord).Property(u => u.Description).OriginalValue;
break;
}
}
context.Dispose();
}
【讨论】: