如何实现具有接口,基础和具体的Repository Pattern

时间:2009-05-22 06:07:37

标签: c# design-patterns repository repository-pattern abstraction

通过IRepository<T>接口,NewsRepository类和News实体,我几乎完成了我的存储库模式的实现。我遇到的问题是试图将常用方法抽象到基础Repository类。

我找不到在NewsRepository中抽象Get方法的方法,因为它包含一个特定的Linq表达式。

我的问题是

1)如何将public T Get(int id)方法抽象到基类?到目前为止我唯一能做到的方法是传入Expression<Func<T,bool>>而不是int,但是那个deos并没有真正抽象出常见的行为,因为每个子类仍然需要传递一个差不多的表达式在每种情况下都相同,即n => n.id == id

2)如何在Update方法中传入子类GetViolations和map方法?我想解决方案可能是通过使用委托,但我无法获得编译的语法

这是一组简化的代码 - 实际上我有一个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();
    }
}

2 个答案:

答案 0 :(得分:2)

  1. L2S既不支持层超类型,也不支持在查询中使用接口成员,这使得重用变得非常困难。一种选择是动态构建表达式树。它有点乱,但如果你把它隔离到你的基类存储库那就不差了。
  2. 以下是一个例子:

    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}
                );
        }
    }
    

    另见http://msdn.microsoft.com/en-us/library/bb397951.aspx

答案 1 :(得分:1)

  1. 拥有layer supertype for entities真的很有帮助。他们将共享Id属性。你不必处理一个表达来表示id proeprty,你只需知道它是什么。

  2. template method pattern。在此模式中,基本Update按顺序执行所有调用帮助程序方法的工作,并且派生类实现这些受保护的抽象帮助程序方法。