0

我正准备开始一个新的 asp.net web 项目,我将使用 LINQ-to-SQL。我使用Mike Hadlow找到的一些信息做了一些工作来设置我的数据层,这些信息使用接口和泛型为数据库中的每个表创建一个存储库。起初我认为这是一种有趣的方法。但是,现在我认为创建一个基础 Repository 类并从它继承以为我需要访问的表创建一个 TableNameRepository 类可能更有意义。

哪种方法可以让我以干净可测试的方式添加特定于表的功能?这是我的存储库实现供参考。

public class Repository<T> : IRepository<T> where T : class, new()
{
    protected IDataConnection _dcnf;

    public Repository()
    {
        _dcnf = new DataConnectionFactory() as IDataConnection;
    }

    // Constructor injection for dependency on DataContext 
    // to actually connect to a database
    public Repository(IDataConnection dc)
    {
        _dcnf = dc;
    }

    /// <summary>
    /// Return all instances of type T.
    /// </summary>
    /// <returns>IEnumerable<T></returns>
    public virtual IEnumerable<T> GetAll()
    {
        return GetTable;
    }

    public virtual T GetById(int id)
    {
        var itemParam = Expression.Parameter(typeof(T), "item");
        var whereExp = Expression.Lambda<Func<T, bool>>
            (
                Expression.Equal(
                    Expression.Property(itemParam, PrimaryKeyName),
                    Expression.Constant(id)
                ), new ParameterExpression[] { itemParam }
            );
        return _dcnf.Context.GetTable<T>().Where(whereExp).Single();
    }

    /// <summary>
    /// Return all instances of type T that match the expression exp.
    /// </summary>
    /// <param name="exp"></param>
    /// <returns>IEnumerable<T></returns>
    public virtual IEnumerable<T> FindByExp(Func<T, bool> exp)
    {
        return GetTable.Where<T>(exp);
    }

    /// <summary>See IRepository.</summary>
    /// <param name="exp"></param><returns></returns>
    public virtual T Single(Func<T, bool> exp)
    {
        return GetTable.Single(exp);
    }

    /// <summary>See IRepository.</summary>
    /// <param name="entity"></param>
    public virtual void MarkForDeletion(T entity)
    {
        _dcnf.Context.GetTable<T>().DeleteOnSubmit(entity);
    }

    /// <summary>
    /// Create a new instance of type T.
    /// </summary>
    /// <returns>T</returns>
    public virtual T Create()
    {
        //T entity = Activator.CreateInstance<T>();
        T entity = new T();
        GetTable.InsertOnSubmit(entity);
        return entity;
    }

    /// <summary>See IRepository.</summary>
    public virtual void SaveAll()
    {
        _dcnf.SaveAll();
    }

    #region Properties
    private string PrimaryKeyName
    {
        get { return TableMetadata.RowType.IdentityMembers[0].Name; }
    }

    private System.Data.Linq.Table<T> GetTable
    {
        get { return _dcnf.Context.GetTable<T>(); }
    }

    private System.Data.Linq.Mapping.MetaTable TableMetadata
    {
        get { return _dcnf.Context.Mapping.GetTable(typeof(T)); }
    }

    private System.Data.Linq.Mapping.MetaType ClassMetadata
    {
        get { return _dcnf.Context.Mapping.GetMetaType(typeof(T)); }
    }
    #endregion
}
4

2 回答 2

5

您不应该为每个表创建一个存储库。
相反,您应该为域模型中存在的每个“实体根”(或聚合根)创建一个存储库。您可以在此处了解有关该模式的更多信息并查看一个工作示例:

http://deviq.com/repository-pattern/

于 2011-02-08T13:23:53.573 回答
1

我很想建议你是否使用具体类型并不重要,就好像你使用依赖注入(城堡?)来创建存储库(这样你可以用不同的缓存等包装它们)然后你的代码库将是无论您采用哪种方式,都不会更明智。

然后只需向您的 DI 询问存储库。例如城堡:

public class Home {
  public static IRepository<T> For<T> {
    get {
      return Container.Resolve<IRepository<T>>();
    }
  }
}

就个人而言,在您发现需要之前,我不会将类型降至最低。

我想您问题的另一半是您是否可以轻松地提供 IRepository 的内存实现以用于测试和缓存目的。为此,我会注意 linq-to-objects 可能会很慢,您可能会发现类似http://www.codeplex.com/i4o的东西很有用。

于 2008-09-19T16:55:01.437 回答