2016-09-26 57 views
1

我有一个大型模型,它已经通过反序列化进行了部分更新。由于它只是部分更新,所以当我将其传递给实体框架更新时,我想忽略任何空值。最终EntityState.Modified已设置,但我遇到的问题是所有字段都已更新。这意味着任何现在空白的东西现在都在数据库中消隐。
是否可以通过设置更改此默认行为或覆盖检查null的方法?看起来,由于上下文期望完整的模型,我不能简单地设置一些值。
我已经通过映射验证了这一点,只有我需要修改和发生相同的行为。忽略上下文更新中的空值

回答

0

这是一个有点乏味的问题,我不得不解决。因为缺乏更直接的解决方案,最终我决定不想尝试像EF的SaveChanges-and-the-likes这样被调用的下游解决问题(即不需要“挂钩到“EF太晚了),而是尽可能高的上游/尽可能早 -

也就是说,这样做后,我得到一个令人满意的反序列化,这是有意义的变种模型,每个实体(在我的用例中,没有可更新的属性代表关系,但只有独立的属性,在E/R说法 - YMMV)

所以,我选择了“填充”助手,沿着:

static void Populate(object from, object to) 
    { 
     var sourceType = from.GetType(); 
     foreach (PropertyInfo target in to.GetType().GetProperties()) 
     { 
      // Is the property at the target object writable and *not* marked 
      // as `[NotMapped]'? 
      var isUpdatable = 
       target.CanWrite && 
       (target.GetCustomAttribute<NotMappedAttribute>(true) == null); 
      if (isUpdatable) 
      { 
       // If so, just find the corresp. property with the same name at the source object 
       // (caller is assumed responsible to guarantee that there is one, and of the same type, here) 
       var source = sourceType.GetProperty(target.Name); 

       var @default = sourceType.IsValueType ? Activator.CreateInstance(sourceType) : null; 
       var equality = (IEqualityComparer)typeof(EqualityComparer<>).MakeGenericType(sourceType).GetProperty("Default", BindingFlags.Public | BindingFlags.Static).GetValue(null); 
       var value = source.GetValue(from); 

       // Test for <property value> != default(<property type>) 
       // (as we don't want to lose information on the target because of a "null" (or "default(...)") coming from the source) 
       if (!equality.Equals(value, @default)) 
       { 
        target.SetValue(to, value, null); 
       } 
      } 
     } 
    } 

其中“从”是刚刚部分以任何反串行化代码填充新鲜实体实例,并在“到”是住在的DbContext(可以是一个EF代理或不)的实际目标实体;

其中NotMappedAttribute是EF的平常。

您通常会在完成“from”实例的反序列化(& /或DTO映射)之后调用Populate,但无论如何,在SaveChanges()获取对DbContext的所有“到“实体 - 显然,我们假设有一个可行的1:1映射”,从“...”到“,Populate的调用者知道/可以弄清楚。

注意我仍然不知道是否有一种更优雅(更直接)的方式来做到这一点,而无需借助反射 - 所以,FWIW。上面的代码

备注

1)可(或应当)可以以各种方式作出更多的防御,这取决于主叫方假设; 2)人们可能想要缓存那些IEqualityComparer的(& /或PropertyInfo的)无论(好)的原因可能会出现 - 在我的情况下,我不需要;

3)最后,我的理解是,第三方librairies如AutoMapper还专门为这一类任务的设计,如果你能承受的额外依赖

“HTH,

+1

我有什么非常相似,我创建了一个映射工厂,负责映射基础架构的各个层次(例如API-> Business-> Data)。我很欣赏Reflection对你来说不是一个好选择。我认为这种情况也不合理。另外,我的工作组审查了AutoMapper,但由于其他原因拒绝了它。感谢您的反馈。 – McArthey

+0

'不错,除了使用像AutoMapper或反射之类的东西外,我希望自己找到了一些不需要入侵EF的东西,但是仍然是上面的帮助者在我的情况下完成了这项工作。无论如何,我确信它可以用于中央,易于重构的位置(我需要以不同的方式做)。 – YSharp

+0

经过审查这个代码效果很好(减去几个空检查),但也许我误解了一些东西?我映射到数据库的结果模型(在这种情况下为'to')仍然包含反射后模型的所有映射属性,这意味着空值在数据层仍然会导致问题。最终,我需要删除包含空值的所有属性。 – McArthey