如何将 IQueryable 组合到一个呼叫中
本文关键字:一个 呼叫 IQueryable 组合 | 更新日期: 2023-09-27 18:31:33
我想将IQueryable
作为参数传递给一个函数,然后该函数将调用实体框架提供程序来执行查询,如下所示:
public ICollection<MyRowType> RunCommand(IQueryable<MyRowType> query)
{
using (var db = new MyDbContext())
{
var result = db.MyRowType
.Include(r => r.RelatedTableA)
.Include(r => r.RelatedTableB)
.Include(r => r.RelatedTableC)
// How do I make the value in `query` run here?
.ToList();
}
}
我基本上将我的数据库调用包装到此方法以返回所有必要的包含,但我不想失去通过 IQueryable<MyRowType>
进行自定义查询的灵活性。
以下是我想要实现的示例:
public ICollection<MyRowType> SomeOtherMethod(string id, SomeValue value = null, SomeOtherValue otherValue = null)
{
var query = Enumerable.Empty<MyRowType>()
.Where(r => r.Id == di);
if (value != null)
query = query.Where(r => r.PropertyOne == value);
if (otherValue != null)
query = query.Where(r => r.PropertyTwo == otherValue);
return RunCommand(query);
}
答案更新:
我将Yacoub Massad和dasblinkenlight的答案结合到这两种方法中:
public static ICollection<MyRowType> RunCommand(Expression<Func<MyRowType, bool>> condition)
{
return Get(t => t.Where(condition));
}
public static ICollection<MyRowType> RunCommand(Func<IQueryable<MyRowType>, IQueryable<MyRowType>> query)
{
using (var db = new DbContext())
{
var includes = db.MyRowType
.Include(r => r.RelatedTableA)
.Include(r => r.RelatedTableB)
.Include(r => r.RelatedTableC)
var result = query(includes)
.ToList();
return result;
}
}
你应该传递Func<IQueryable<MyRowType>,IQueryable<MyRowType>>
而不是像这样传递IQueryable<MyRowType>
:
public ICollection<MyRowType> RunCommand(Func<IQueryable<MyRowType>,IQueryable<MyRowType>> func)
{
using (var db = new MyDbContext())
{
IQueryable<MyRowType> q = db.MyRowType
.Include(r => r.RelatedTableA)
.Include(r => r.RelatedTableB)
.Include(r => r.RelatedTableC);
var result = func(q);
return result.List();
}
}
然后你可以像这样使用它:
var result = RunCommand(q => q.Where(....));
或者使用其他 LINQ 方法,如下所示:
var result = RunCommand(q => q.Where(....).OrderBy(x => ...).Take(10));
请注意,您不能传递将选择与 MyRowType
不同的类型的查询。如果你想要它,那么你可以像这样使方法泛型:
public ICollection<T> RunCommand<T>(Func<IQueryable<MyRowType>,IQueryable<T>> func)
{
using (var db = new MyDbContext())
{
IQueryable<MyRowType> q = db.MyRowType
.Include(r => r.RelatedTableA)
.Include(r => r.RelatedTableB)
.Include(r => r.RelatedTableC);
var result = func(q);
return result.List();
}
}
现在你可以像这样使用它:
var result = RunCommand<SomeOtherType>(q => q.Where(x => ....).Select(x => ....));
从IQueryable<T>
中提取表达式并不容易,并且您无法直接应用传递给方法的queryable
。但是,由于您似乎试图通过传递IQueryable<T>
而不更改输出类型来限制查询,因此更改 API 以采用条件而不是IQueryable<T>
可能更容易,如下所示:
public ICollection<MyRowType> RunCommand(Expression<Func<MyRowType,bool>> condition) {
using (var db = new MyDbContext()) {
var result = db.MyRowType
.Include(r => r.RelatedTableA)
.Include(r => r.RelatedTableB)
.Include(r => r.RelatedTableC)
.Where(condition)
.ToList();
}
}
如果使用 LINQ to 实体谓词合并器,则可以将自定义条件与在 RunCommand
方法中执行的常见准备步骤相结合:
public ICollection<MyRowType> SomeOtherMethod(string id, SomeValue value = null, SomeOtherValue otherValue = null) {
Expression<Func<MyRowType,bool>> condition =
r => r => r.Id == di;
if (value != null)
condition = condition.And(r => r.PropertyOne == value);
if (otherValue != null)
condition = condition.And(r => r.PropertyTwo == otherValue);
return RunCommand(query);
}