简体   繁体   English

如何使用接口,基础和具体实现存储库模式

[英]How to implement Repository Pattern with interface, base and concrete

I have almost completed implementing my repository pattern by having a IRepository<T> interface, a NewsRepository class and a News entity. 我几乎已经通过具有IRepository<T>接口, NewsRepository类和News实体来实现我的存储库模式。 The problem I ran into was trying to abstract out common methods to a base Repository class. 我遇到的问题是试图将通用方法抽象为基本的Repository类。

I could not find a way to abstract the Get method in the NewsRepository as it contains a specific Linq expression. 我找不到在NewsRepository抽象Get方法的方法,因为它包含特定的Linq表达式。

My questions are : 我的问题是

1) How do I abstract to a base class the public T Get(int id) method please? 1)如何将public T Get(int id)方法抽象到基类? The only way I have done it so far is by passing in Expression<Func<T,bool>> instead of an int, but then that deosn't really abstract out common behaviour as each sub-class will still need to pass in an expression that is almost identical in each case ie n => n.id == id . 到目前为止,我这样做的唯一方法是传入Expression<Func<T,bool>>而不是int,但是这样就不会真正抽象出常见的行为,因为每个子类仍需要传入一个在每种情况下都几乎相同的表达式,即n => n.id == id

2) How do I pass into the base class on the Update method the sub-class GetViolations and map methods please? 2)如何将Update类的子类GetViolations和map方法传入基类? I imagine the solution is possibly by using delegates, but I couldn't get the syntax to compile 我想解决方案可能是通过使用委托,但是我无法获取语法进行编译

This is a simplified set of the code - in practice I have a Save method which does Update and Insert rather than just the Update shown here. 这是一组简化的代码-实际上,我有一个Save方法,它执行Update和Insert,而不仅仅是此处显示的Update。

public interface IRepository<T>
{
    T Get(int id);
    void Update(T item);
}

public class NewsRepository : IRepository<News>
{
    private Table<News> _newsTable;
    public NewsRepository(string connectionString)
    {
        _newsTable = new DataContext(connectionString).GetTable<News>();
    }

    public News Get(int id)
    {
        return _newsTable.SingleOrDefault(n => n.NewsId == id);
    }

    public void Update(News item)
    {
        var errors = item.GetRuleViolations();
        if (errors.Count > 0)
            throw new RuleException(errors);

        News dbNews = _newsTable.SingleOrDefault(n => n.NewsId == item.NewsId);
        map(dbNews, item);

        _newsTable.Context.SubmitChanges();
    }

    private void map(News dbNews, News news)
    {
        dbNews.Title = news.Title;
        dbNews.Article = news.Article;
    }
}

public class Repository<T> where T : class
{
    protected Table<T> _table;

    public Repository(Table<T> t)
    {
        _table = t;
    }

    //How do i do this??! - This doesn't compile due to T no having a NewsId
    public T Get(int id)
    {
    return _table.SingleOrDefault(n => n.NewsId == id);
    }

    //This seems to be a solution, but it's not really abstracting common behaviour as each
    //sub-class will still need to pass in the same linq expression...
    public T Get(Expression<Func<T,bool>> ex)
    {
        return _table.SingleOrDefault(ex);
    }

    public void Update(T item)
    {
        //How is it possible to pass in the GetRuleViolations and map functions to this method?
        var errors = item.GetRuleViolations();
        if (errors.Count > 0)
            throw new RuleException(errors);

        T dbNews = _table.SingleOrDefault(n => n.NewsId == item.NewsId);
        map(dbNews, item);

        _table.Context.SubmitChanges();
    }
}
  1. L2S supports neither layer supertypes nor using interface members in queries, which makes reuse quite difficult. L2S不支持层超类型,也不支持在查询中使用接口成员,这使得重用非常困难。 One option is to dynamically build an expression tree. 一种选择是动态构建表达式树。 It's a bit messy, but if you isolate it to your base class repository it's not that bad. 有点混乱,但是如果将其隔离到基类存储库中,还不错。

Here is an example: 这是一个例子:

public interface IEntity
{
    int Id { get; }
}

public partial class News : IEntity
{
}

public class Repository<T> where T : class, IEntity
{

    private readonly DataContext _db;

    public Repository(DataContext db)
    {
        _db = db;
    }

    public T Get(int id)
    {
        Expression<Func<T, bool>> hasId = HasId(id);
        return _db.GetTable<T>().Single(hasId);
    }

    // entity => entity.Id == id;   
    private Expression<Func<T, bool>> HasId(int id)
    {
        ParameterExpression entityParameter = Expression.Parameter(typeof (T), "entity");
        return Expression.Lambda<Func<T, bool>>(
            Expression.Equal(
                Expression.Property(entityParameter, "Id"),
                Expression.Constant(id)
                ),
            new[] {entityParameter}
            );
    }
}

See also http://msdn.microsoft.com/en-us/library/bb397951.aspx 另请参阅http://msdn.microsoft.com/en-us/library/bb397951.aspx

  1. It really helps to have a layer supertype for entities . 为实体提供层超类型确实有帮助。 They will share an Id property. 他们将共享一个ID属性。 You won't have to deal with an expression to represent the id proeprty, you'll just know what it is. 您无需处理表示id属性的表达式,您只需知道它是什么即可。

  2. The template method pattern . 模板方法模式 In this pattern your base Update does all the work calling helper methods in order, and your derived classes implement those protected abstract helper methods. 在这种模式下,基础Update会按顺序执行所有工作,调用辅助方法,而派生类将实现那些受保护的抽象辅助方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 具体服务应该取决于具体的存储库或接口吗? - Should concrete service depend on concrete repository or interface? 这种设计模式是否有名称,其中具体类实现了一个特定接口,该接口实现了 CRUD 操作的基本接口? - Is there a name for this design pattern where a concrete class implements a specific interface which implements a base interface for CRUD operations? C#:如何使用包含具体值的具体字典中的接口值的 IReadOnly 字典实现接口 - C#: How to implement an interface with an IReadOnly dictionary containing interface values from a concrete dictionary containing concrete values 使用具体类实现接口方法 - Implement an interface method with a concrete class 如何转换实现接口的具体类列表 - How to cast a list of concrete classes which implement an interface C#如何实现具体类不同的接口? - C# How to implement interface where concrete classes differs? 如何在C#存储库上正确实现接口 - How to correctly implement an interface on a C# repository 如何使用通用存储库模式实现 AutoMapper - How to Implement AutoMapper with Generic Repository Pattern 如何正确实施存储库模式? - How to implement the repository pattern the right way? 如何动态子类化(或实现)基类(或接口)? - How to dynamically subclass (or implement) a base class (or an interface)?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM