2017-07-11 27 views
0

假設我有一個像這樣的東西代碼更新記錄的通用數據訪問層方法:如何通過在方法多lambda表達式

public virtual void Update<P>(Expression<Func<T, P>> excludeColumn, params T[] items) 
{ 
     foreach (T item in items) 
     { 
      _entities.Entry(item).State = EntityState.Modified; 
      _entities.Entry(item).Property(excludeColumn).IsModified = false; 
     } 

     _entities.SaveChanges(); 
} 

在這裏,我以excludeColumn參數有關的更新不計列,我傳遞的值在該參數這樣

_companyProfileRepository.Update(x => x.EmailAddress, records); 

x => x.EmailAddress是我傳遞到通用Update方法的表達式。我的問題是我想要傳入多個列到Update方法,因爲有時我需要排除多於一列,但我的方法不支持多列機制。

任何人都可以幫我解決這個問題嗎?

+1

我的理解是EF已經跟蹤更改您的實體和只更新修改的屬性,那麼,爲什麼你需要排除列? – saille

+1

,因爲我用空屬性發送進行更新,即使數據庫中有值,因爲這是敏感數據,我不想在視圖中顯示,但用戶可以更新其他值 –

+0

您可能想要考慮添加例如實體和視圖之間的一個圖層,例如視圖模型 - 請參閱此問題:https://stackoverflow.com/questions/11064316/what-is-viewmodel-in-mvc。 – saille

回答

0

對於多列的情況,您可以添加一個接受未修改列的名稱的重載。喜歡的東西:

public virtual void Update<TEntity>(IEnumerable<string> excludeColumnNames, params TEntity[] items) 
    { 
     foreach (var item in items) 
     { 
      _entities.Entry(item).State = EntityState.Modified; 
      foreach (var cn in excludeColumnNames) 
      { 
       _entities.Entry(item).Property(cn).IsModified = false; 
      } 

     } 
     _entities.SaveChanges(); 
    } 
+0

爲什麼永遠使用通用庫反模式? http://www.ben-morris.com/why-the-generic-repository-is-just-a-lazy-anti-pattern/如何正確使用Repository模式:https://martinfowler.com/eaaCatalog/repository .html – saille

+1

使用泛型類型約束,通用存儲庫基類允許代碼重用。在爲不同的(但非常相似的)表實施存儲庫時,我發現它非常有用。 – buffjape

+0

除了重用之外,您發現某個表的更新方法與另一個表的更新方法不同,順便說一下,OP剛剛遇到過這個問題。 – saille

-1

我有一個類似的方法,但使用linq-to-sql。這是一種有點不同的方法,但是這種方法很好。您可能需要將其調整爲與EF一起使用。

public class Data 
{ 
    public static void Update<T>(Func<T, bool> where, Action<T> change) 
    { 
     IEnumerable<T> items = ((IEnumerable<T>)myDataContext.GetTable(typeof(T))).Where(where); 

     foreach (T item in items) 
     { 
      change(item); 
     } 

     myDataContext.SubmitChanges(); 
    } 
} 

我用這樣的:

Data.Update<User>(u => u.Id == 3, u => 
{ 
    u.Name = "John"; 
    u.Age = 25; 
    u.Email = "[email protected]"; 
}); 

雖然這可能不是直接回答這個問題,我認爲這是相關的,會有所幫助。

+0

myDataContext從哪裏來 - 它的範圍是什麼?爲什麼要使用靜態的Update()方法?這是什麼模式 - 它似乎是一個「靜態通用庫」anitpattern! – saille

+0

@saille這只是示例代碼。數據上下文應該根據用戶配置,連接字符串等來創建。此外,這是不相關的,因爲它在EF中是不同的。此外,它是減少重複代碼的簡單幫手,僅此而已,應該僅在有意義時才使用。沒有錯,除非有人使用它。 – Guilherme

+0

@downvoter關心評論? – Guilherme

0

使用存儲庫模式,你可以在東西實際上有意義,而不是隱瞞意向通用/抽象代碼包裝你的EF數據層。 Repository Pattern的Web上有很多示例實現,但我認爲這是一種反模式,and I'm not alone

例如一個UserProfileRepository能有一個這樣的接口:

public interface IUserProfileRepository 
{ 
    void UpdateUserProfile(IUserProfile p); 
} 

這是一個有意義的人閱讀你的代碼,因爲它使得它的意圖明確的那種抽象的。此外,上述代碼改變的唯一原因是,如果實際上存儲IUserProfile的方式發生了變化,並且在更新UserProfile時需要做一些特殊的處理,您可以在某處放置它。

比較你:

void Update<TEntity>(IEnumerable<string> excludeColumnNames, params TEntity[] items) 

其掩蓋的意義時,調用此方法是在你的代碼來實現許多不同的結果灑,以及是否有特殊處理,以更新特定實體類型,你無處可放它,所以它最終會被推上一層,並在每次需要時重複。

另外考慮獲取一個實體並更新它是兩個非常不同的操作。你可能會獲得一個實體的所有屬性,但只能更新其中的一些,我相信你是在你的問題中提到的。我認爲英孚對實體的讀寫方式「感覺」幾乎相同,是一種可怕的抽象,會導致很大的痛苦和痛苦。讀取和寫入數據是非常不同的用例,如CQRS pattern所證明的。

0

如果你想通過多列,然後將它們傳入...
數組或列表是常用的方法。

public virtual void Update<P>(List<Expression<Func<T, P>>> excludeColumns, params T[] items) 
{ 
    foreach (T item in items) 
    { 
     foreach (Expression<Func<T, P>> excludeColumn in excludeColumns) 
     { 
      _entities.Entry(item).State = EntityState.Modified; 
      _entities.Entry(item).Property(excludeColumn).IsModified = false;  
     } 
    } 

    _entities.SaveChanges(); 
} 

那將是罰款,只要每列具有相同類型P.