簡體   English   中英

什么是IRepository以及它用於什么?

[英]What is a IRepository and what is it used for?

什么是IRepository? 為什么使用它,簡短而簡單的例子不會受到傷害。

MVC促進了關注點的分離,但這並不止於MVC級別。

數據訪問本身就是一個問題。 它應該在MVC的M位,即模型中完成。 你如何構建你的模型取決於你,但人們通常會遵循久經考驗的模式(為什么重新發明輪子?)。 存儲庫模式是當前的標准。 然而,不要指望一個簡單的公式,因為變化與開發人員差不多。

IRepository只是您創建的接口(它不是MVC或ASP.NET或.NET的一部分)。 它允許您將存儲庫與實際實現“分離”。 解耦很好,因為它意味着你的代碼...:

  1. 您的代碼更可重用。 這簡直太好了。
  2. 您的代碼可以使用Inversion of Control(或依賴注入)。 這樣可以很好地保持您的關注點。 它特別好,因為這允許單元測試......
  3. 您的代碼可以進行單元測試。 這在具有復雜算法的大型項目中尤其有用。 它無處不在,因為它增加了您對所使用技術的理解以及您嘗試在軟件中建模的域。
  4. 您的代碼將圍繞最佳實踐構建,遵循通用模式。 這很好,因為它使維護更容易。

因此,在賣給你脫鈎之后,你的問題的答案是IRepository是你創建的一個接口,並且你使你的存儲庫繼承。 它為您提供了可靠的類層次結構。

我通常使用通用的IRepository:

IRepository

TEntity就是一個實體。 我使用的代碼是:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Wingspan.Web.Mvc
{
    public interface IRepository<TEntity> where TEntity : class
    {
        List<TEntity> FetchAll();
        IQueryable<TEntity> Query {get;}
        void Add(TEntity entity);
        void Delete(TEntity entity);
        void Save();
    }
}

該接口的具體實現是:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Linq;

using Wingspan.Web.Mvc;

namespace ES.eLearning.Domain
{
    public class SqlRepository<T> : IRepository<T> where T : class
    {
        DataContext db;
        public SqlRepository(DataContext db)
        {
            this.db = db;
        }

        #region IRepository<T> Members

        public IQueryable<T> Query
        {
            get { return db.GetTable<T>(); }
        }

        public List<T> FetchAll()
        {
            return Query.ToList();
        }

        public void Add(T entity)
        {
            db.GetTable<T>().InsertOnSubmit(entity);
        }

        public void Delete(T entity)
        {
            db.GetTable<T>().DeleteOnSubmit(entity);
        }

        public void Save()
        {
            db.SubmitChanges();
        }

        #endregion
    }
}

這允許我寫:

SqlRepository<UserCourse> UserCoursesRepository = new SqlRepository<UserCourse>(db);

其中db是一個注入到服務中的DataContext實例。

使用UserCoursesRepository,我現在可以在我的Service類中編寫方法,如:

public void DeleteUserCourse(int courseId)
        {
            var uc = (UserCoursesRepository.Query.Where(x => x.IdUser == UserId && x.IdCourse == courseId)).Single();
            UserCoursesRepository.Delete(uc);
            UserCoursesRepository.Save();
        }

現在在我的控制器中,我可以寫:

MyService.DeleteUserCourse(5);
MyService.Save();

使用這種模式,您的應用程序的開發變得更像是一個裝配線,導致一個非常簡單的控制器。 裝配線的每一部分都可以獨立於其他任何部分進行測試,因此蟲子被扼殺在萌芽狀態。

如果這是一個冗長,笨拙的答案,那是因為真正的答案是:

購買Steven Sanderson的書Pro ASP.NET MVC 2 Framework並學習在MVC中思考。

IRepository是您希望實現存儲庫模式時指定的接口。 正如@Brian Ball所說,它不是.NET的一部分,它是您創建的界面。

使用存儲庫模式的開發人員廣泛推薦使用接口來實現。 例如,在我正在開發的應用程序中,我有5個存儲庫。 4具體和1通用。 每一個都從一個IRepository繼承而來,這確保了我不會在實施過程中遇到問題。

至於代碼示例,我會嘗試:

interface IRepository<T> where T : class {
    IQueryable<T> Select();
}

實現為通用存儲庫:

public class Repository<T> : IRepository<T> where T : class {
    public IQueryable<T> Select() {
        return this.ObjectContext.CreateObjectSet<T>();
    }
}

作為專門的存儲庫實現:

public class EmployeeRepository : IRepository<Employee> {
    public IQueryable<Employee> Select() {
        return this.ObjectContext.Employees;
    }
}

Repository<T>EmployeeRepository實現了IRepository ,但是它們執行查詢的方式略有不同。 通用存儲庫必須先創建T的對象集,然后才能嘗試執行任何操作。

請記住, Repository<T>應該被鎖定到接口,而EmployeeRepository可以實現更專業的方法來完成更復雜的邏輯。

我希望這對你有所幫助。

IRepository不是.Net框架中的已定義類型。 通常,當您看到名為該接口的接口時,程序將使用存儲庫模式( https://web.archive.org/web/20110503184234/hbp://hiblogatingrhinos.com/nhibernate/archive/2008/10/08/ the-repository-pattern.aspx )。 通常,當人們使用此模式時,他們將創建一個所有存儲庫都遵循的接口。 這樣做有很多好處。 一些好處是代碼反匯編和單元測試。

這也很常見,因此可以利用IoC( http://en.wikipedia.org/wiki/Inversion_of_control )。

存儲庫是一種抽象,它表示任何底層和任意數據存儲,就好像它是內存中的對象集合一樣

由於常見的做法和系統限制,這個定義變成了一種更實用的形式,作為內存中對象的集合,代表了一些底層和任意數據存儲,可能是一個斷開連接的數據存儲 在引擎蓋下,存儲庫可以鏈接到數據庫,平面文件,內存中的對象集合或者您可能想到的任何其他內容。 存儲庫的用戶不關心。

所以IRepository是接口契約,它定義了Api代碼如何希望客戶端代碼與存儲庫交互。 這通常包括添加,更新,刪除和獲取合同,例如,存儲庫合同的這個非常常見的示例:

public interface IRepository<TEntity> where TEntity : class
{
    List<TEntity> GetAll();
    void Add(TEntity entity);
    void Delete(TEntity entity);
    void Save();
}

但出於幾個原因,我更喜歡使用不同的界面。

首先,您通常不會單獨使用存儲庫,您可能會將其與工作單元格一起使用,因此存儲庫不應具有Save()方法。 它可能有一個Update(T entity)方法 - 但為什么呢? 您從存儲庫收到的對象將自動更新/更新,就像您從任何類型的對象集合中收到的任何其他對象一樣,因為您已檢索到對象本身的引用。 (例如:如果你的TEntity是一個Person對象,你得到了人“Chuck”,並且你將他的姓氏從“Bartowski”更改為“Carmichael”,那么該存儲庫可能已經更新了所述實體。如果這看起來很脆弱請注意,實現Update(T entity)方法沒有任何問題。)

其次,大多數存儲庫應該能夠處理斷開連接的環境。 如果您的解決方案沒有此要求,您仍然可以創建一個處理斷開連接方案的界面,並且只是將其保留為未實現。 現在你已經為未來做好了准備。

最后,我們的契約對存儲庫的真實性質更有意義 - 存儲庫中的對象集合代表一些任意數據存儲,可能是一個斷開連接的數據存儲

public interface IRepository<TEntity> where TEntity : class
{

    List<TEntity> GetAll();
    List<TEntity> Get(Func<TEntity, bool> where);
    void Insert(TEntity entity);
    void Insert(IEnumerable<TEntity> entities);
    void Remove(TEntity entity);
    void Remove(IEnumerable<TEntity> entities);

    void SyncDisconnected(TEntity entity, bool forDeletion = false);
    void SyncDisconnected(IEnumerable<TEntity> entities, bool forDeletion = false);
}

如果為所有實體定義基類,讓我們將其稱為DomainObject ,並為其指定Id字段,則可以執行以下操作:

public interface IRepository<TEntity> where TEntity : DomainObject
{
    TEntity GetById(object Id);

    List<TEntity> GetAll();
    List<TEntity> Get(Func<TEntity, bool> where);
    void Insert(TEntity entity);
    void Insert(IEnumerable<TEntity> entities);
    void Remove(TEntity entity);
    void Remove(IEnumerable<TEntity> entities);

    void SyncDisconnected(TEntity entity, bool forDeletion = false);
    void SyncDisconnected(IEnumerable<TEntity> entities, bool forDeletion = false);
}

如果您不喜歡可選參數forDeletion ,則可以添加允許同步已刪除對象的方法:

    void SyncDisconnectedForDeletion(TEntity entity);

您需要這樣做的原因是,在大多數情況下,同步斷開連接的對象以進行刪除與同步斷開連接的對象以進行添加或修改是不兼容的。 (試試吧。你會親眼看到對商店的刪除要求與添加或修改的要求有很大差異)。 因此,接口應該定義一個契約,因此實現可以在兩者之間進行辨別。

您可以針對任何基礎數據存儲的任何存儲庫實現此接口,連接或斷開連接,包括對基礎數據存儲(如實體框架)的其他抽象。

暫無
暫無

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

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