3

有些閱讀告訴我我的存儲庫(1)應該什麼都不做,只能通過配置的(注入的)數據提供者直接進行CRUD操作,但是在小型項目中我經常會添加整個服務層以獲得更多。Repository的職責應該如何有限?

例如,我的應用處理「銀行」分支機構和客戶端。現在,如果我的用戶爲每個工作會話「打開」一個分支,並且每個新客戶都分配給該分支,我感覺傾向於注入一個我編寫的AppContext單例,以跟蹤諸如當前打開的分支的環境應用屬性,放入我的ClientRepository中,並讓該對象將正確的BranchID分配給新的客戶端記錄。

我知道這是不正確的最純粹的意義,但我在這裏談論基本2層應用程序,用戶界面和數據。唯一的業務邏輯就是查詢數據庫。有沒有更適合我在這裏使用的模式?

(1)The Repository Pattern

+0

特別含糊,我什麼都聽不懂。你的系統是什麼(語言,圖書館,操作的基本概念)?你的情況是什麼「儲存庫」和「分支」?這也應該說明標識符的含義。 – 2012-12-09 11:26:38

回答

1

我個人同意,就像你在第一段所述信息庫應爲「乾淨」成爲可能。

根據經驗,我通過在CRUD函數中編寫業務邏輯代碼來「欺騙」,這往往要求其他存儲庫是屬性。

在ASP.net中工作時,我利用泛型和事件處理。

public class Repository<T, DC> 
     where T : class 
     where DC : DataContext, new() 
{ 
    public delegate void RecordInsertedHandler(object s, BasicEventArgs<T> e); 
    public event RecordInsertedHandler RecordInserted; 

    public delegate void RecordDeletedHandler(object s, BasicEventArgs<T> e); 
    public event RecordDeletedHandler RecordDeleted; 

    public delegate void RecordObtainedHandler(object s, BasicEventArgs<T> e); 
    public event RecordObtainedHandler RecordObtained; 

    public delegate void RecordUpdatedHandler(object s, BasicEventArgs<T> e); 
    public event RecordUpdatedHandler RecordUpdated; 

    protected DC dc; 

    public Repository(string connectionString="") 
    { 
     dc = ((connectionString == null) || (connectionString == "")) ? new DC() : DynamicTypes.Instantiate<DC>(connectionString); // See code below for DynamicTypes: 

    } 

    // There are similar functions for other events not shown. 
    protected void OnRecordInserted(BasicEventArgs<T> obj) 
    { 
     if (RecordInserted != null) 
     { 
      RecordInserted(this, obj); 
     } 
    } 

    // Only the Insert is shown here. 
    private void Insert(T obj) 
    { 
     dc.GetTable<T>().InsertOnSubmit(obj); 
     dc.SubmitChanges(); 

     OnRecordInserted(new BasicEventArgs<T>(obj)); 
    } 
} 

其基本思想是您可以在正常的CRUD函數的正確位置觸發/調用這些事件。我認爲你的版本庫將是ASP.net頁面或Windows窗體的成員。那些容器會成爲「事件監聽者」,因爲他們可以操縱UI。

動態類型:

public static class DynamicTypes 
{   
    public static T Instantiate<T>(params object[] args) 
    { 
     return (T)Activator.CreateInstance(typeof(T), args); 
    } 
} 

BasicEventArgs:

public class BasicEventArgs<T> : EventArgs 
{ 
    private T _Data; 
    private string _Message; 

    public BasicEventArgs(T data, string message="") : base() 
    { 
     _Data = data; 
     _Message = message; 
    } 

    public T Data 
    { 
     get { return _Data; } 
     set { _Data = value; } 
    } 

    public string Message 
    { 
     get { return _Message; } 
     set { _Message = value; } 
    } 
} 

庫:

public class BranceshRepository : Repository<Branch, YourDataContext> 
{ 
    public BranchesRepository(string connectionString="") : base(connectionString) 
    { 
    } 
} 

public class ClientsRepository : Repository<Client, YourDataContext> 
{ 
    public ClientsRepository(string connectionString="") : base(connectionString) 
    { 
    } 
} 

現在,例如,我們有一個ASP.net頁:

public partial class MyPage : Page 
{ 
     protected ClientsRepository _ClientsRepository; 
     protected BranchesRepository _BranchesRepository; 

     protected void Page_Load(object s, EventArgs e); 
     { 
      _ClientsRepository = new ClientsRepository(...); 
      _BranchesRepository = new BranchesRepository(...); 

      _BranchesRepository.RecordInserted += new Repository<Branch,YourDataContext>.RecordInsertedHandler(OnBranchInserted); 
      _ClientsRepository.RecordInserted += new RepositoryM<Client, YourDataContext>.RecordInsertedHandler(OnClientInserted); 
     } 

     protected void OnBranchInserted(object s, BasicEventArgs<Branch> e) 
     { 
      /* e.Data is your newly-inserted branch with the newly-generated Id 
       from the database. You may save this branch to Session for 
       later use when your user inserts a new client. 
       */ 
     } 

     protected void OnClientInserted(object s, BasicEventArgs<Client> e) 
     { 
       Branch currentBranch = (Branch)Session["Branch"]; 
       e.Data.BranchId = currentBranch.Id; 
       _ClientsRepository.Update(e.Data);     
     } 

     // Control event handlers not shown, like CreateClient_BT_Click, for example. 
} 

這樣,您不需要在ClientsRepository中注入單例,並且您可以在這些事件處理程序中完全訪問您的UI。

1

在我們的團隊中,我們追求(至少大約3或4年)這個完美的世界理念,所有的商業邏輯都必須完全從商業邏輯中去除。所以我們建立了很多服務。

我們相信,在這個完美的世界裏,如果你有一個特定的範圍,你可以爲它創建一個服務。正如Mickael之前提到的「ClientsRepository」將爲客戶提供SCRUD(s - search),我們只稱之爲ClientsService(如服務中告訴你有關客戶的一切)。在這裏,你有威脅,當在極端壓力下或最後期限不知情的開發者或一個人看到這樣的代碼:

public ModifyClientResponse ModifyClient(ModifyClientRequest request){ 

    ClientEntity clientEntity=new ClientEntity(); 
    ModifyClientResponse clientResponse = new ModifyClientResponse(); 

    ClientMapper mapper=new ClientMapper(); 
    mapper.Map(request.Client, clientEntity); 

    clientEntity.Update(); 

    ClientDTO responseClientDto=new ClientDTO(); 
    mapper.Map(clientEntity, responseClient); 

    clientResponse.Client=responseClientDto; 

    return clientResponse 
} 

這是,我認爲,非常簡單。同樣的開發者可以完成一項任務,例如「當客戶送貨地址更新時,我們需要在尚未批准或發貨的發票中更改他的地址數據」時,它會變成如下所示:

public ModifyClientResponse ModifyClient(ModifyClientRequest request){ 

    ClientEntity clientEntity=new ClientEntity(); 
    ModifyClientResponse clientResponse = new ModifyClientResponse(); 

    ClientMapper mapper=new ClientMapper(); 
    mapper.Map(request.Client, clientEntity); 

    clientEntity.Update(); 

    if(clientEntity.Address.DataModification==DataModification.Modified){ 
    // all the silly business logics about address being changed 
    } 

    ClientDTO responseClientDto=new ClientDTO(); 
    mapper.Map(clientEntity, responseClient); 

    clientResponse.Client=responseClientDto; 

    return clientResponse 
} 

現在沒有人會責怪開發者,並且規模小,效率足夠好,足夠好。但從長遠來看,這將成爲一場災難。始終改變的要求將越來越難以維護,基本上我們認爲它違背了SOA和大部分SOLID開發原則。它減少了服務單一責任 - 各種不好的東西。然而,我想回到那個,這應該發生在「完美世界」:我們的地方上面的代碼是通過發送消息與客戶DTO處理任何人來處理。因此,發票服務可以連接到「客戶端修改」並使用處理程序,執行適當的處​​理。通過這種方式,我們可以讓客戶解耦 - 如果需要,他們可以在另一個數據源/服務器/星球/任何地方。

我們還試圖保持這更乾淨,沒有自定義消息處理程序,但與工作流。我們有一個內部工作流引擎(幾乎像Windows工作流基礎或jboss),它可以根據某些事件訂閱和觸發工作流。

目前我們正在研究ECA規則引擎(http://en.wikipedia.org/wiki/Event_condition_action)的創建,這將使這更加靈活。但足夠了解我們:)

如果我要實現它,那麼您的任務將是僅執行CRUD並且觸發消息的服務以及處理這些消息並執行業務邏輯的另一個服務。但那將是完美的世界方法,可能估計會嚇到某個人爬上梯子。我會盡可能以最簡單的方式做到這一點,即將所有內容聯繫在一起,但遵守良好代碼的基本原則,只是爲了讓這個系統突然發展成開放和閉合銀行的大規模產品而不那麼痛苦分支機構。

簡而言之:我是aggree,版本庫應該很清晰,除了數據之外不應該有任何東西。