2016-09-26 28 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