是否可以手动修改IQueryable表达式

本文关键字:修改 IQueryable 表达式 是否 | 更新日期: 2023-09-27 18:21:50

我很确定我知道答案是否定的,但作为最后的尝试,我想我应该在这里问这个问题。

我首先使用EF代码以通常的方式查询表

_context.Set<Foo>().Where(f => f.Bar == 999);

它创建了以下表达式(我刚刚写了这个,所以它可能是错误的)。

{SELECT 
[Extent1].[Test] AS [Test], 
[Extent1].[Test2] AS [Test2], 
FROM [dbo].[Foo] AS [Extent1]
WHERE 19 = [Extent1].[Bar]}

现在,是否可以手动修改此查询以将表名更改为Foo10?(可能不是)

如果做不到这一点,有人知道我可以先在代码中"延迟绑定"表名的方法吗?

你可能想知道"为什么是肮脏的黑客?"和往常一样,这是一个数据库的遗留问题,它有一些设计问题,无法更改。

提前谢谢。

Ps。我知道我可以使用Database.SqlQuery,但我宁愿不使用。

是否可以手动修改IQueryable表达式

为什么不在模型上使用TPT继承?

类似于@Krizz的回答,但您避免使用动态LINQ。

使用您的评论:

如果一个特定参数的值为1,则在Foo1中查找,如果它在Foo2中查找2,依此类推

所以,你可以这样做:

var query = ctx
   .Foos
   .OfMyType(value)
   .Where(f => f.Bar == 999) // f.Bar is on the base/abstract entity.
   .ToList();

其中OfMyTypeIQueryable<T>:上的自定义扩展方法

public static IQueryable<T> OfMyType<T>(this IQueryable<T> source, string value)
{
   switch (value)
   {
      case "1":
         return source.OfType<Foo1>();
      case "2":
         return source.OfType<Foo2>();
      // etc, etc
   }
}

大多数(如果不是全部的话)属性都将在抽象的"Foo"实体上,并且您为每个表创建派生实体,每个表都有自己的支持表。

这样,"消耗"代码(例如进行查询的代码)就不必关心不同的表/Foo,它们只需将"神奇的值"传递到您的存储库(希望是您正在使用的存储库),然后您就可以无声地切换到您想要的表。

这样行吗?

假设您有合理数量的表,我会将它们全部添加到模型中,并创建一个所有类都将实现的公共接口,然后选择合适的模型并使用Dynamic Linq进行查询。

我不确定这是否有效,没有检查过,也没有使用";EF码优先";,但这是我会尝试的东西:

假设您的表Foo有字段-BarPubX,并且让X是相应表所依赖的字段?

然后,我将定义接口:

interface IFoo 
{
   int Bar { get; set; }
   string Pub { get; set; }
   int X { get; set; }
}

然后每个表在模型中都有自己的类:

[Table("Foo1")]
class Foo1 : IFoo 
{
   public int Bar { get; set; }
   public string Pub { get; set; }
   public int X { get; set; }
}
[Table("Foo2")]
class Foo2 : IFoo 
{
   public int Bar { get; set; }
   public string Pub { get; set; }
   public int X { get; set; }
}

然后你可以像下面这样过滤它们:

 IQueryable GetAdequateFoo(int X)
 {
    switch (X) // you could use reflection here to dynamically call the given Set<Foo#>()
    {
       case 1:
         return _context.Set<Foo1>();
       case 2:
         return _context.Set<Foo2>();
       default:
         return null;
    }
 }
 IFoo GetFooByBarAndX(int bar, int X)
 {
    IQueryable context = GetAdequateFoo(X);
    return context.Where("it.Bar == @0", bar).Cast<IFoo>(); 
 }

以下是如何使用新的/修改过的表达式(撰写本文时为EF core 5.0)创建新的IQueryable。

var expression = query.Expression;
//modify your expression usually by building a new one or rebuilding using an ExpressionVisitor
var newQuery = query.Provider.CreateQuery(expression);

注意:我在IQueryable上搜索编辑表达式,这是第一个出现的问题,但细节集中在一个非常具体的用例上,而更普遍的问题还没有得到回答。。。