如何将DbEntityEntry的OriginalValues转换为强类型和分离对象?

时间:2014-09-10 21:31:59

标签: c# entity-framework validation

我目前正在测试和修改我的api服务。主Update函数调用验证和事件处理程序,但严重依赖于DbEntityEntry。 DbEntityEntry的问题,或者更确切地说是它的OriginalValues属性,是它在访问实体的不存在的属性时不会抛出异常或提醒编译器。正在寻找一个更强大的类来翻译OriginalValues,但我已经空了。

以下是我的开始:

public override Item Update(Item revisedItem, DbContext context) {
    DbEntityEntry entry = context.Entry<Item>(revisedItem);
    DbPropertyValues originalValues = entry.OriginalValues;
    ...
    validateType(revisedItem.Type, entry.OriginalValues.GetValue<Nullable<decimal>>("Tipe"));  //GetValue won't catch the misspelling of "Type"
    ...
    return revisedItem; 
}

这很麻烦,因为我突然要测试以确保OriginalValues返回我期望的内容,以防止打字错误。我非常愿意告知DbPropertyValues它携带的数据是Item的数据。我只是使用OriginalValues.ToObject()并将它放在一个实体上,但是有两个相同EntityKey的实体使我对实体跟踪的熟悉程度变得复杂。

使用不反射的OriginalValues有什么替代方法?它还应该能够与其修改后的实体共存。

感谢您的时间和耐心,因为我正致力于重建对强类型语言的理解。

1 个答案:

答案 0 :(得分:0)

我需要快速继续工作,所以我想出了一个体面但不太理想的解决方案。我创建了一个类,它本质上是DbPropertyValues的包装器,名为DbEntityPropertyValues,它接受一个类型参数。调用GetValue时,它使用反射(bleh)来检查EntityType是否具有给定属性。与DbPropertyValues不同,如果属性不存在,则会抛出错误。这在运行时不是很有用,但它会在测试期间更容易地清除问题。

构造函数的设计方式绕过了DbPropertyValue的模拟不足。 DbEntityPropertyValues有两个构造函数,一个接受一个DbPropertyValue,一个接受一个实体。在正常操作期间将使用DbProperyValue,在模拟期间将使用实体。这是代码。

public class DbEntityPropertyValues<EntityType> where EntityType : MyEntity {

    private readonly Dictionary<string, object> entityKeyValuePairs = new Dictionary<string, object>();

    public DbEntityPropertyValues (DbPropertyValues dbPropertyValues) {
        IEnumerable<string> dbPropertyNames = dbPropertyValues.PropertyNames;

        foreach(var prop in dbPropertyNames) {
            entityKeyValuePairs.Add(prop, dbPropertyValues.GetValue<Object>(prop));
        }
    }

    //Intended only for testing.
    //A detached entity gets passed in instead of DbPropertyValues which can't be mocked.
    public DbEntityPropertyValues (CompanyEntity entity) {
        IEnumerable<PropertyInfo> entityProperties = typeof(EntityType).GetProperties().AsEnumerable();

        foreach (var prop in entityProperties) {
            entityKeyValuePairs.Add(prop.Name, entity.GetType().GetProperty(prop.Name).GetValue(entity, null));
        }
    }

    public T GetValue<T> (string propertyName) {
        if (!typeof(T).Equals(typeof(EntityType).GetProperty(propertyName).PropertyType)) {
            throw new ArgumentException(String.Format("{0} of type {1} does not exist on entity {2}", propertyName, typeof(T), typeof(EntityType)));
        }

        return (T)entityKeyValuePairs[propertyName];
    }
}

欢迎提出批评和建议。