2010-09-13 38 views
1

我開始了一個ASP.net Web項目應用程序,以瞭解如何使用EF4。在我的項目中,我定義了3層(DAL => Entity Framework 4,BLL =>業務邏輯層,UI)。 BLL和DAL共享使用EF4的模板特徵生成的POCO。從EF4的上下文中退出時加載Poco引用實體的好策略是什麼?

,比如我有「用戶」波科類,看起來像這樣:

public partial class User 
{ 
    #region Primitive Properties 

    public virtual System.Guid Id 
    { 
     get; 
     set; 
    } 

    public virtual string Name 
    { 
     get; 
     set; 
    } 

    public virtual string Password 
    { 
     get; 
     set; 
    } 

    public virtual string Email 
    { 
     get; 
     set; 
    } 

    public virtual bool MarkedForDeletion 
    { 
     get; 
     set; 
    } 

    #endregion 
    #region Navigation Properties 

    public virtual Role Role 
    { 
     get { return _role; } 
     set 
     { 
      if (!ReferenceEquals(_role, value)) 
      { 
       var previousValue = _role; 
       _role = value; 
       FixupRole(previousValue); 
      } 
     } 
    } 
    private Role _role; 

    public virtual ICollection<Article> Articles 
    { 
     get 
     { 
      if (_articles == null) 
      { 
       var newCollection = new FixupCollection<Article>(); 
       newCollection.CollectionChanged += FixupArticles; 
       _articles = newCollection; 
      } 
      return _articles; 
     } 
     set 
     { 
      if (!ReferenceEquals(_articles, value)) 
      { 
       var previousValue = _articles as FixupCollection<Article>; 
       if (previousValue != null) 
       { 
        previousValue.CollectionChanged -= FixupArticles; 
       } 
       _articles = value; 
       var newValue = value as FixupCollection<Article>; 
       if (newValue != null) 
       { 
        newValue.CollectionChanged += FixupArticles; 
       } 
      } 
     } 
    } 
    private ICollection<Article> _articles; 

    public virtual Status Status 
    { 
     get { return _status; } 
     set 
     { 
      if (!ReferenceEquals(_status, value)) 
      { 
       var previousValue = _status; 
       _status = value; 
       FixupStatus(previousValue); 
      } 
     } 
    } 
    private Status _status; 

    #endregion 
    #region Association Fixup 

    private void FixupRole(Role previousValue) 
    { 
     if (previousValue != null && previousValue.Users.Contains(this)) 
     { 
      previousValue.Users.Remove(this); 
     } 

     if (Role != null) 
     { 
      if (!Role.Users.Contains(this)) 
      { 
       Role.Users.Add(this); 
      } 
     } 
    } 

    private void FixupStatus(Status previousValue) 
    { 
     if (previousValue != null && previousValue.Users.Contains(this)) 
     { 
      previousValue.Users.Remove(this); 
     } 

     if (Status != null) 
     { 
      if (!Status.Users.Contains(this)) 
      { 
       Status.Users.Add(this); 
      } 
     } 
    } 

    private void FixupArticles(object sender, NotifyCollectionChangedEventArgs e) 
    { 
     if (e.NewItems != null) 
     { 
      foreach (Article item in e.NewItems) 
      { 
       item.Author = this; 
      } 
     } 

     if (e.OldItems != null) 
     { 
      foreach (Article item in e.OldItems) 
      { 
       if (ReferenceEquals(item.Author, this)) 
       { 
        item.Author = null; 
       } 
      } 
     } 
    } 

    #endregion 
} 

因爲所有屬性都標有虛擬EF4應以訪問POCO的所有數據創建一個代理類。此外,我已啓用數據庫上下文的延遲加載。

當我想顯示一個用戶的詳細信息我有休耕情形:

  • UI =>實例從BLL(UsersManager)一類,並調用方法GetUserByEmail(串電子郵件),它返回一個用戶。

  • BLL =>在UsersManager類型的GetUserByEmail(string email)方法中,我從DAL(UsersDataManager)實例化一個類並調用一個返回用戶的方法GetUserByEmailFromDAL(string email)。

  • DAL =>在GetUserByEmailFromDAL(字符串電子郵件)我實例化一個上下文,爲用戶查詢並返回它。

的問題是,因爲只有DAL知道的情況下,它退出波蘇斯導航關係被置空後的功能,我不具備存取權限的任何屬性使其設置。

,如果我做myUser.Role.Name我得到這樣的錯誤:

Role = 'user1.Role' threw an exception of type 'System.ObjectDisposedException' 
The ObjectContext instance has been disposed and can no longer be used for operations that require a connection. 

爲了繞過我決定修改,以便它告訴他們要急於負載的導航屬性我的方法問題當我需要他們時。此修改後,我在DAL方法是這樣的:

public User User(string email, bool loadRelationships) 
     { 
      User user = null; 
      if (!loadRelationships) 
      { 
       user = (from p in dbContext.Users where p.Email.Equals(email) select p).FirstOrDefault<User>(); 
      } 
      else { 
       user = (from p in dbContext.Users.Include("Role").Include("Status") select p).FirstOrDefault<User>(); 
      } 

      return user; 
     } 

與此修改仍是個問題exists..i沒有進入相關實體導航實體......等等,例如,如果一個角色類型有如果我想要這樣的東西的權限集合:

User user1 = UserManager("[email protected]"); 
foreach(Permission perm in user1.Role.Permissions) 
Console.WriteLine(perm.Name); => here i'd get an error like the one mentioned earlier. 

當Poco連接到數據庫上下文時,延遲加載工作。有沒有可用於加載導航屬性的機制或策略,就像我的場景一樣?

謝謝。

回答

0

您的傳統演示/業務/數據三層架構不適用於延遲加載。 UI不應直接導致查詢執行。

如果您希望UI層能夠延遲加載相關實體,則必須通過業務層將來自DAL的上下文表達出來。這可能不是一個好主意,因爲如果你允許這樣做,你可能會不經意間在UI中加載更多數據的查詢。你也打破了你對問題的分離。

上面的按照參數按需加載相關數據的方法是一種更好的方法。

+0

所以爲了加載角色的導航屬性(就像在我的例子中)我應該查詢角色本身..類似於角色myUsersRole = RoleManager.GetRoleWithId(user1.Role.id);並在DAL中調用與UsersDataManager類似的方法(..)你也可以給出一些可以用於延遲加載的arhitectures的例子(爲了google他們)?謝謝戴夫! – 2010-09-13 14:21:14

+0

@Sorin:是的,我認爲你在正確的軌道上。您正在使用的三層體系結構將責任置於DAL和BLL上,以正確顯示* UI所需的內容,僅此而已。我在我的ASP.NET MVC項目中使用了一個存儲庫模式的延遲加載。這是一個「平坦」的架構,更適合延遲加載。您仍然必須小心,不要過度使用延遲加載,否則可能會遇到性能問題。 – 2010-09-13 14:36:42

相關問題