动态构建IQueryable

时间:2015-11-19 21:58:44

标签: c# entity-framework linq-to-entities

我有以下IQueryable

        IQueryable<Class1> queryable =
            (from c1 in DbContext.Set<Class1>()
             from c2 in DbContext.Set<Class2>()
             from c3 in DbContext.Set<Class3>()
             where c1.Id == c2.Class1Id
             && c2.Id == c3.Class2Id
             && c3.ValueAsString == val
             select c1);

在上面的例子中,val是一个字符串。但是,Class3还有其他几个成员:

    public string ValueAsString { get;private set; }
    public int? ValueAsInteger { get; set; }
    public DateTime? ValueAsDate { get; set; }
    public decimal? ValueAsDecimal { get; set; }
    public bool? ValueAsBoolean { get; set; }

我需要修改IQueryable,具体取决于'val'的类型,它可能是上述5种类型之一。是否可以将IQueryable构造为:

        IQueryable<Class1> queryable =
            (from c1 in DbContext.Set<Class1>()
             from c2 in DbContext.Set<Class2>()
             from c3 in DbContext.Set<Class3>()
             where c1.Id == c2.Class1Id
             && c2.Id == c3.Class2Id                 
             select c1);

然后根据'val'的类型添加最终执行前的位置?例如,如果val是小数,则追加

c3.ValueAsDecimal == val

2 个答案:

答案 0 :(得分:0)

对于您的任务来说,使用表达式而不是类似sql的linq会更方便。正如我所看到的,您的类通过主键相互连接,如果使用属性,此查询看起来大致如下:

Expression<Func<Class3, bool>> filterExpression = GetFilterExpression(val); //returns expression bases on val type

var queryable = DbContext.Set<Class1>()
                             .Include(cl1=>cl1.Class2.Class3) //or .Include(cl1=>cl1.Class2.Select(cl2=>cl2.Class3)) depending on your object relationships
                             .Where(filterExpression);

如果您需要为Class1类型的根实体加载Class2和Class3实例,则使用此处包含。如果您不需要它们,可以跳过.Include()结构。

GetFilterExpression示例:

public Expression<Func<Class1, bool>> GetFilterExpression(string value) 
{ 
    return cl1 => cl1.Class2.Class3.ValueAsString == value;
}

答案 1 :(得分:0)

这实际上很简单,你可以在条件通过时调用.Where(...)。您只需预先选择所有值c1c2c3,在添加.Where(...)来电后,您可以选择c1值从结果。像这样:

var q = (
    from c1 in dbContext.Set<Class1>()
    from c2 in dbContext.Set<Class2>()
    from c3 in dbContext.Set<Class3>()
    where c1.Id == c2.Class1Id
    && c2.Id == c3.Class2Id
    select new { c1, c2, c3 }
);
object var = ...; // Some value
if (var is decimal)
{
    q = q.Where(x => x.c3.ValueAsDecimal == (decimal)var);
}
else if (var is DateTime)
{
    q = q.Where(x => x.c3.ValueAsDate == (DateTime)var);
}
// TODO: Add other types of 'var' 

var queryable = q.Select(x => x.c1);