【问题标题】:Conditional projection with LINQ to SQL使用 LINQ to SQL 进行条件投影
【发布时间】:2013-02-05 00:51:17
【问题描述】:

是否可以使用 LINQ to SQL 进行条件投影?假设我有一个名为 PersonTable 的 SQL 表。在 C# 中,我有几个类:

public interface Person
{
 int employeeType; //1 is employee, 2 is manager
 String name;
}

还有两个派生类。为简单起见:

public class Employee : Person {}
public class Manager : Person {}

现在,我想使用 LINQ to SQL 根据employeeType 投影到适当的派生类:

IQueryable<IPerson> = PersonTable.Select(x => //x.employeeType == 1 ? new Employee { } : x == 2 {new Manager {} )

这对于这种情况是可以的,但是我有一种情况,我试图实例化 7 种不同的可能派生类型,所以条件会变得又长又丑。此外,在我的真实世界场景中,接口/派生类有 15 个左右的属性要填充;这也会很快变得又长又丑。

我的第一次尝试是编写一个返回适当类型的表达式树,但这不起作用,因为我需要知道参数表达式的值才能正确调用 Expression.MemberInit。对于像这样使用 LINQ to SQL 的大型条件初始化,哪种解决方案可能是最好的。

我不能使用表继承,因为我正在投影中创建数据传输对象。我也考虑过使用 where 和 union,但表达式树路径似乎更有趣,因为我将有一个位置来维护代码,而不是每次引入新的派生类时 - 如果这是一个甚至是一个选项。

【问题讨论】:

  • 这里的工厂不实用吗?也许一个依赖注入框架可以帮助你?除了你(可以理解)不想有一个大的、讨厌的 if/else 字符串之外,我不完全理解其他要求。
  • 这里不可能有工厂。这发生在我投影到域对象的 DAL 的 LoadAll 方法中。 LINQ to SQL 不喜欢我调用工厂。
  • 我认为你不能直接这样做。您将过滤与选择混为一谈。做这样的事情真的不是什么好主意。你最好做一些外部连接并带回一个匿名类型(带有一堆 NULL)并在你的应用程序代码中强制转换。
  • 我仍在尝试为您找出一个不好的解决方案。 x 是什么?它是在代码中预先确定的,还是 PersonTable 中的列?
  • 您是否尝试过使用Expression&lt;Func&lt;Person, bool&gt;&gt; 类型的变量?您可以对它们做一些很酷的技巧,同时仍然可以很好地处理延迟执行的 SQL 查询。

标签: c# linq-to-sql


【解决方案1】:

也许你可以这样做,

PersonTable.Where(p => p.employeeType == 1)
    .Select(p => new Employee { ... })
    .Cast<IPerson>()
    .Concat(
        PersonTable.Where(p => p.employeeType == 2)
            .Select(p => new Manager { ... })
            .Cast<IPerson>());

你也可以试试,

PersonTable.Select(p => 
     p.employeeType == 1 ? (IPerson)(new Employee { ... }) :
     p.employeeType == n ? (IPerson)(new Other { ... }) :
     (IPerson)(new Manager { ... }));

或者,如果不需要是IQueryable

PersonTable.AsEnumerable().Select(p => {
    switch(p.employeeType)
    {
        case 2:
            return Manager { ... };

        default:
            return Employee { ... };   
    }});

【讨论】:

  • 不幸的是,这必须是IQueryable,因为它由需要限制返回结果的控制器使用。不幸的是,如果不重复大量代码,我认为没有办法做到这一点。
  • 我尝试了您的第一个示例,但没有成功。它抛出了 System.NotSupportException:Union 或 Concat 中的类型不能用层次结构构造。我在调用Concat() 时尝试将结果转换为 Enumerable,但随后收到了NullReferenceException: value cannot be null。所以我添加了 null-coalescs 来返回空的 Enumerables,这也没有帮助。我是否发现了使用 LINQ to SQL 无法解决的问题? :)
  • @Furynation 看起来很可能,我很难过,但是,您的表的每一行都有相同的架构......可能更简单地进行客户端转换。
  • 这就是我现在正在做的事情。 Person 类不是抽象的(即使它确实应该是),我会在必要时进行转换。感谢您的意见!
猜你喜欢
  • 1970-01-01
  • 2011-06-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多