1

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

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

我的问题是

1)我如何抽象基类的public T Get(int id)方法好吗?到目前为止,我所做的唯一方法是传递Expression<Func<T,bool>>而不是int,但是然后没有真正地抽象出常见的行为,因为每个子类仍然需要传递一个几乎相同的表达式即n => n.id == id

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

这是一个简化的代码集 - 在实践中我有一个保存方法,更新和插入,而不仅仅是更新显示在这里。

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
  1. 它确实有助于有一个layer supertype for entities。他们将分享Id财产。你不必处理表达式来表示id proeprty,你只需知道它是什么。

  2. The template method pattern。在这个模式中,你的基本Update会完成所有按顺序调用helper方法的工作,并且你的派生类实现了那些受保护的抽象帮助器方法。

2
  1. L2S既不支持层超类型,也不使用在查询接口部件,这使得再利用非常困难的。一种选择是动态构建表达式树。这有点麻烦,但是如果你把它分离到你的基类库中,它并不是那么糟糕。

下面是一个例子:

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