2016-11-20 62 views
0

我有以下情形:连接表动态与纯LINQ

  1. 可以有每超过100列两个随机表。
  2. 其中一个表有另一个外键。
  3. 用户从这两个表中选择一组列,我们应该从db中选择并作为JSON对象发回。限制是它应该是纯LINQ(而不是DynamicLINQ)。

我试图答案我能找到玩弄表情,但我所取得的最好是作为IEnumerable的结果,这是不可接受的,因为我需要IQueriable后对其进行过滤。我在前后查找,但我发现的唯一工作变体是DynamicSQL here,但我不允许使用它。

任何想法,非常感谢。

更新:作为一个例子,我有两个随机表加入fk,所以它只是一个常规的加入,如from t1 in Table1 join t2 in Table2 on t1.field1 = t2.field2。我需要的只是能够将选择表达式传递给此联接,并基于包含要选择的列的字符串集合构建,例如,如果我有{"t1.field1", "t1.field2", "t2.field3"},那么联接应该看起来像from t1 in Table1 join t2 in Table2 on t1.field1 = t2.field2 select new {t1.field1, t1.field2, t2.field3}

+0

将你的连接写入分贝数据视图。并将此视图映射到您的实体。 – user1681317

+0

@ user1681317,正如我所说的,随机表中会有随机的表,所以我需要在select中使用匿名类型进行动态连接。我很积极,这可以通过表达式的帮助来实现,但是我在这个主题方面的知识并不完善,我无法实现这个 – KorsaR

+0

请您详细说明您的问题。如果你提供你的实际查询并告诉我们你想要动态化的部分(这是一个单词吗?),这将有很大的帮助。 – Sefe

回答

0

从列列创建实例的问题在于,由于.NET是类型安全的,因此您需要一个可以实例化的类型。当您使用匿名类(即没有类名的new关键字)时,编译器将为您创建一个类。它是匿名的,但在编译时仍然存在(你可以在你选择的反编译器中检查这个)。

如果你想在运行时真正完全动态你必须在执行时动态创建和编译你的类。为此,您可能需要查看System.CodeDomSystem.Reflection.Emit名称空间,它们都包含允许您在运行时动态创建类型的类。然而,这将是一项相当大的工作,它怀疑是值得你花时间的。然后你想访问这些对象中的数据,所以你可能不得不去寻找dynamic变量。

更应该做的是在编译时创建一个常规类并在LINQ查询中实例化它。此类将包含全部可能的属性,您可以设置。当你实例化它时,你不必填写所有的字段。

一旦你有了你的类,你就可以动态地创建表达式来实例化它。这就是System.Linq.Expressions名称空间中的类所适用的。 Expression类包含允许您创建所需表达式树的工厂方法。

要创建表达式树,首先必须分解要建模的表达式。尤尔的Join表达将类似于这个(假设你的容器类被命名为DataContainer):

(t1, t2) => new DataContainer { 
    Value1 = t1.field1, 
    Value2 = t1.field2, 
    Value3 = t2.field3 
} 

这种表达已经在其部分被分割根据自己的优先级:

  • Lambda表达式由lambda运算符=>启动:LambdaExpression,由Expression.Lambda创建
  • 参数t1t2位于lambda运算符的左侧:​​,与Expression.Parameter
  • 的对象实例化new DataContainer创建拉姆达操作者的右侧:用Expression.Assign
  • 的属性来创建BinaryExpression,:NewExpression,与Expression.New
  • =发起的初始化块内的作业创建作业离开:MemberExpression,用Expression.Property创建
  • 该属性取消参考.field1MemberExpression,用Expression.Property创建
  • 参数访问t1:​​,与Expression.Parameter创建(但你重用你的lambda表达式创建的参数表达式)

正如你可以看到,这是一个相当繁琐相比,只是写下来表达式(或使用动态LINQ)。我将与子表达式t1.field1举例说明这一点:

在这一点上,你会已经创造了左侧的拉姆达的t1参数:

ParameterExpression t1Param = Expression.Parameter(typeof(Table1), "t1"); 

你重用你的访问属性:

MemberExpression t1field1Property = Expression.Property(t1Param, "field1"); 

这个表达式在你创建你的任务时使用,你将在实例化表达式中使用这个表达式,它将用于你的lamdba表达式的右边,沿着w ith其他需要的表达。你也可以把它写成一棵树(除了要重用的参数表达式之外)。

快乐编码!