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

时间:2012-01-28 23:44:43

标签: c# linq-to-entities code-first iqueryable

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

我首先使用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? (可能不是)

如果不这样做,是否有人知道我可以在代码中“晚点绑定”表名的方式?

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

提前致谢。

聚苯乙烯。我知道我可以使用Database.SqlQuery但不愿意。

4 个答案:

答案 0 :(得分:2)

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

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

使用您的评论:

  

如果特定参数的值为1,请查看Foo1,如果它的2看起来在Foo2中,依此类推

所以,你可以这样做:

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,他们只是将“魔术值”传递给你的存储库(希望你使用它),然后就可以了静静地切换到你想要的桌子。

那会有用吗?

答案 1 :(得分:1)

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

我不确定这是否有效,没有检查过,并且没有使用过“EF代码优先”,但我会尝试这样做:

假设您的表格Foo包含字段 - BarPubX,让X成为相应表所依赖的字段上?

然后,我会定义interface:

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>(); 
 }

这只是未经过测试的建议并且是从头上写的,如果我错了,请不要投票,并指出任何潜在的问题。

答案 2 :(得分:0)

这不是我建议的,但是你可以通过ToString()查询将SQL语句放到变量中然后用字符串替换表名。然后SQL执行那个SQL?

臭臭和黑客但可能吗?

答案 3 :(得分:-1)

以下是如何使用新的/修改过的表达式(在撰写本文时为 EF 核心 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 上编辑表达式,这是第一个出现的问题,但细节随后集中在一个非常具体的用例上,更一般的问题尚未得到解答......

>