我继承了一个系统,该系统使用 Castle Windsor IRepository 模式从 DAL 中抽象出来,即 LinqToSQL。
我可以看到的主要问题是 IRepository 只实现了 IEnumerable。因此,即使是最简单的查询也必须从数据表中加载所有数据,才能返回单个对象。
目前使用情况如下
using (IUnitOfWork context2 = IocServiceFactory.Resolve<IUnitOfWork>())
{
KpiFormDocumentEntry entry = context2.GetRepository<KpiFormDocumentEntry>().FindById(id, KpiFormDocumentEntry.LoadOptions.FormItem);
这使用 lambda 过滤,就像这样
public static KpiFormDocumentEntry FindById(this IRepository<KpiFormDocumentEntry> source, int id, KpiFormDocumentEntry.LoadOptions loadOptions)
{
return source.Where( qi => qi.Id == id ).LoadWith( loadOptions ).FirstOrDefault();
}
所以它成为一个很好的扩展方法。
我的问题是,我怎样才能使用相同的接口/模式等,同时实现 IQueryable 以正确支持 LinqToSQL 并获得一些严重的性能改进?
IRepository 的当前实现/接口如下
public interface IRepository<T> : IEnumerable<T> where T : class
{
void Add(T entity);
void AddMany(IEnumerable<T> entities);
void Delete(T entity);
void DeleteMany(IEnumerable<T> entities);
IEnumerable<T> All();
IEnumerable<T> Find(Func<T, bool> predicate);
T FindFirst(Func<T, bool> predicate);
}
然后这是由像这样的 SqlClientRepository 实现的
public sealed class SqlClientRepository<T> : IRepository<T> where T : class
{
private readonly Table<T> _source;
internal SqlClientRepository(Table<T> source)
{
if( source == null ) throw new ArgumentNullException( "source", Gratte.Aurora.SHlib.labelText("All_TableIsNull",1) );
_source = source;
}
//removed add delete etc
public IEnumerable<T> All()
{
return _source;
}
public IEnumerator<T> GetEnumerator()
{
return _source.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
目前的问题是,在上面的示例中,.Where 正在调用“GetEnumerator”,然后将所有行加载到内存中,然后查找我们需要的行。
如果我更改 IRepository 以实现 IQueryable,我将无法实现所需的三个方法,因为它们在 Table 类中不是公共的。
我想我应该将 SQLClientRepository 更改为这样定义
public sealed class SqlClientRepository<T> : IQueryable<T>, IRepository<T> where T : class
然后实现必要的方法,但我不知道如何传递表达式等,因为它们是 Table 类的私有成员,就像这样
public override Type ElementType
{
get { return _source.ElementType; } //Won't work as ElementType is private
}
public override Expression Expression
{
get { return _source.Expression; } //Won't work as Expression is private
}
public override IQueryProvider Provider
{
get { return _source.Provider; } //Won't work as Provider is private
}
任何帮助都非常感谢将其从“加载后遍历数据库中的每一行”移动到“选择 x 其中 id=1”!