我正在尝试使用原子上下文编写一个C#存储库,并且觉得这对于闭包的使用来说是一个完美的情况,但我不能完全理解如何在C#中完成它。我将此作为我的存储库中的主要方法:
...
protected virtual IQueryable<T> AsQueryable()
{
return _context.ObjectSet<T>().AsQueryable();
}
...
与此同时,我使用以下方法派生类:
...
public IQueryable<Arc> ByRun(Run run)
{
IQueryable<Arc> query = from o in AsQueryable()
from r in o.Runs
where r.Id == run.Id
select o;
return query;
}
...
我希望更改我的查询方法以返回IEnumerable并快速处理上下文,所以想要使用(像这样):
...
protected virtual IEnumerable<T> AsEnumerable()
{
using (IContextUnitOfWork unitOfWork = new EFUnitOfWork())
{
return unitOfWork.ObjectSet<T>().ToList();
}
}
...
问题当然是,一旦处理了上下文,在生成的IEnumerable集上调用LINQ将失败。因此,我的想法是我应该捆绑ByRun()方法并将其传递给AsEnumerable()以用作闭包。
虽然不是我原来的语言风格,但我学会了Ruby中的闭包。在那里,我想要做的就是看起来像这样的混合伪代码:
ByRun(Run run)
AsEnumerable do |query|
from o in query
from r in o.Runs
where r.Id == run.Id
select o;
end
end
AsEnumerable方法将打开上下文,执行传入的操作,然后返回。一旦我理解了语法,我确信我能做到这一点,所以我正在寻找以这种方式实现的所需的AsEnumerable和ByRun方法。
答案 0 :(得分:1)
如果我正确理解了这个问题,你想在任何查询上都有一个包装器,以确保在结束时调用AsEnumerable
并在查询之后放置上下文?
如果是这样(假设你的基类是T参数的通用),试试这个:
protected virtual IEnumerable<T> AsEnumerable(Func<ObjectSet<T>, IQueryable<T>> query)
{
using (IContextUnitOfWork unitOfWork = new EFUnitOfWork())
{
return query(unitOfWork.ObjectSet<T>()).AsEnumerable();
}
}
用法示例:
public IEnumerable<Arc> ByRun(Run run)
{
return AsEnumerable(query => from o in query
from r in o.Runs
where r.Id == run.Id
select o);
}
此处AsEnumerable
的参数是lambda表达式,其中包含将ObjectSet<T>
作为唯一参数并返回IQueryable<T>
的任何委托。因此,它在逻辑上等效于在派生类中包含以下代码:
public IEnumerable<Arc> ByRun(Run run)
{
using (IContextUnitOfWork unitOfWork = new EFUnitOfWork())
{
return (from o in unitOfWork.ObjectSet<T>()
from r in o.Runs
where r.Id == run.Id
select o).AsEnumerable();
}
}