簡體   English   中英

實現一個支持實體對象的懶惰借用的存儲庫?

[英]implement a repository that supports lazy loaing for the entity objects?

反正有沒有實現一個使用活動目錄(或任何其他數據源而不是關系數據庫)作為數據源的存儲庫,並且可以獲得能夠延遲加載其關聯的實體對象?

一個例子:

在我們將要開發的各種應用程序中經常使用兩個類

class User
{
   public string DisplayName {get; set;}
   public string UserID {get; set;}
   public string Email {get; set;}
   public string WorkPhone {get; set;}
   // etc.
   public string IList<Group> Groups {get; private set;}
   public User Manager {get; set;}
}

class Group
{
   public string DisplayName {get; set;}
   public string Email {get; set;}
   // etc.
   public IList<User> Members {get; private set;}
   public User Owner {get; private set;}
}

我希望能夠在將來的所有應用程序中重用這兩個類。 對於某些應用程序, UserGroup的數據源現在將是活動目錄,但在將來,我們可能想要使用某些數據庫或數據庫和活動目錄的混合。 為了重用代碼,我將使用存儲庫模式設計兩個存儲庫MySqlDBRepositoryActiveDirectoryRepository以便我檢索和存儲UserGroup

假設我們已經有一個活動目錄庫,可用於獲取文本中表示的用戶信息,即您可以以字符串格式獲取用戶名,電子郵件,經理ID。 我需要實現一個可以與Entity框架或NHibernate大致相同的方式使用的存儲庫,即

 var user = _activeDirectoryRepository.GetUserByUserID("bryan");

 foreach(var group in user.Groups) 

     Console.WriteLine(group.Manager.DisplayName);

最重要的是, user.groupsgroup.Manager都應該自動延遲加載。 我該如何實現_activeDirectoryRepository.GetUserByUserID("bryan")

是的,這是解決問題的好方法。

定義一個接口來表示存儲庫的操作,例如:

public interface IAccountRepository 
{ 
   User GetUserByAccountName(string accountName);

   List<User> GetUsers(Group group); 
   List<Group> GetGroups(User user); 

   // ... etc...
} 

然后創建一個業務邏輯層以將存儲庫映射到對象:

public class Accounts
{ 
   IAccountRepository _repository; 

   public Accounts(IAccountRepository repository) 
   { 
      _repository = repository; 
   } 

   public List<User> GetUsers(Group group) 
   { 
      return _repository.GetUsers(group); 
   } 

   public List<Group> GetGroups(User user) 
   { 
      return _repository.GetGroups(user); 
   } 

   public User GetUserByAccountName(string accountName)
   {
       return _repository.GetUserByAccountName(accountName); 
   }



   // etc...
} 

然后使用:

static void Main(string[] args) 
{ 
   // Load from the MSSQL repository. 
   Accounts accounts = new Accounts(new MSSQLAccountRepository());

   User user = accounts.GetUserByAccountName("someuser"); 

   //...

}

另請參閱: C#中的存儲庫模式教程

我希望能夠在我們的所有應用程序中重用這兩個類。

好的,我建議重新評估這個想法。

重復使用[通常]是一種謬誤

將這些類移動到鏈接到多個應用程序的可重用庫中,您獲得的收益到底是什么?

您將這些類移動到與多個應用程序鏈接的可重用庫中的痛苦到底是什么?

我很有信心,如果你走這條路線,你會體驗到相當多的痛苦得不償失。

我不想將User,Group類定義(源代碼)從一個應用程序復制到另一個應用程序。

為什么? 這真的讓你有什么收獲?

通過單擊“添加引用”與復制並粘貼代碼文件目錄並單擊“添加現有項”,您真實希望節省多少時間?

您第一次更改此庫並在某個應用程序中創建錯誤時,您認為您將失去多少時間,而不是您進行更改的應用程序? 您需要花多少時間來管理鏈接到多個不同應用程序的多個版本的共享庫? 你認為你浪費了多少時間來過度概括這個庫的概念,而不僅僅是為手頭的應用程序做了什么? 當您在需要更多實體的域中使用用戶和組時,需要多長時間來擴展用戶和組?

如果你繼續這樣做,我願意打賭你會失去比你獲得更多的東西。

經過一番思考,我發現這個解決方案可能會很好。

ActiveDirectoryUserRepository ,我可以創建一個繼承自User的內部類ProxyUser ,它接受對ActiveDirectoryUserRepository的引用。 ProxyUser應在第一次調用時返回Groups屬性。


// User.cs
public class User
{
    public virtual string Name { get; set; }
    public virtual string DisplayName {get; set;}
    public virtual string Email { get; set; }

    public virtual IList<Group> Groups { get; set; }
}

// Group.cs
public class Group
{
    public virtual string Name { get; set; }
    public virtual string Email { get; set; }

    public virtual IList<User> Members { get; set; }
}

//  ProxyUser.cs. It should be in the same assembly as ActiveDirectoryUserRepository 

internal class ProxyUser : User
{

   private ActiveDirectoryUserRepository _repository ;
   internal ProxyUser(ActiveDirectoryUserRepository repository)
   {
       _repository = repository;
   }

   internal string IList<string> GroupNames { get; set; }

   private IList<Group> _groups;
   public override IList<Group> Groups 
   { 
      get
      {
         if (_groups == null)
         {
            if (GroupNames != null && GroupNames.Count > 0)
            {
                _groups = new List<Group>();
                foreach(string groupName in GroupNames)
                   _groups.Add(_repository.FindGroupByName(groupName);
            }
         }
         return _groups;
       }

       set
       {
           _groups = value;
       }
    }
}

// ProxyGroup.cs

internal class ProxyGroup : Group
{
    // This class should be similar to ProxyUser
}

// ActiveDirectoryUserRepository.cs

public class ActiveDirectoryUserRepository
{
    public User FindUserByName(string name)
    {
         DirectorySearcher searcher = new DirectorySearcher();

         // ...
         // set up the filter and properties of the searcher
         // ...

         Result result = searcher.FindOne();
         User user = new ProxyUser(this)
         {
             Name = result.Properties["displayName"][0],
             Email = result.Properties["email"][0],
             GroupNames = new List<string>()
         };

         foreach(string groupName in result.Properties["memberOf"])
         {
             user.GroupNames.Add(groupName);
         }

         return user;
    }

    public Group FindGroupByName(string name)
    {
        // Find the Group, which should be similar to FindUserByName
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM