【问题标题】:Linq AddRange() for objects derived from interfaceLinq AddRange() 用于从接口派生的对象
【发布时间】:2016-04-15 18:54:52
【问题描述】:

我正在尝试使用 Entity Framework 6 (EF) 在 Visual Studio 2015 上的 WPF 中使用 LINQ 获得结果。结果需要出现在一个ListView 中以供员工测试。我有两个 EF 实体:DrugTestsAlcoholTests。在我的项目中,我有一些视图模型可以将它们映射到:DrugTestViewModelAlcoholTestViewModel,它们都派生自接口 ITestViewModel

这两个虚拟机共享许多属性,同时也有自己独特的属性(因此需要两个实体)。我正在使用 LINQ 返回一个Task<ObservableCollection<ITestViewModel>>,首先从DrugTests 实体中获取:

var query = (from dt in context.DrugTests 
            .Where(x => x.employeeID.Equals(employeeId))
            select new DrugTestViewModel
            {
                EmployeeId = dt.employeeID,
                TestType = "Drug",
                OrderedDate = dt.orderedDate,
                // set other properties
            } 
).ToList();

然后我尝试使用这个添加到查询中:

query.AddRange(from at in context.AlcoholTests
                   .Where(x => x.employeeID.Equals(employeeId))
               select new AlcoholTestViewModel
               {
                   EmployeeId = at.employeeID,
                   TestType = "Alcohol",
                   // set other properties...
               }
    );

它在AddRange() 上给出了以下异常:

参数 1:无法从 'System.Linq.IQueryable<MySolution.ViewModel.AlcoholTestViewModel>''System.Collections.Generic.IEnumerable<MySolution.ViewModel.DrugTestViewModel>'

我做错了什么?

【问题讨论】:

  • 您的问题在于queryList<DrugTestViewModel>,而您正在尝试将AlcoholTestViewModel 添加到其中。
  • 尝试用ToList<ITestViewModel>()替换ToList()
  • @Alex 老实说,我不介意,但有一次你好心问:)
  • @IvanStoev 只是想提高您的声誉并帮助其他人更好地注意到答案:)
  • @Alex 我非常感谢!

标签: c# .net wpf entity-framework linq


【解决方案1】:

有点晚了,但我想分享另一个解决方案。我会这样使用Concat

var query=...
var query2=..
var result= query.AsEnumerable<ITestViewModel>().Concat(query2);

这样您就可以保持延迟执行,以防您还不需要具体化结果。

【讨论】:

  • 有趣的想法。但是Cast 抛出“LINQ to Entities 仅支持转换 EDM 基元或枚举类型。”所以它应该是AsQueryable。如果两个具体类具有不同的字段,这也会引发异常 - “DbUnionAllExpression 需要具有兼容集合 ResultTypes 的参数。”:(
  • 是的,发布后我正在考虑,如果两个查询没有投影相同的列。我认为这个解决方案需要调用AsEnumerable。谢谢@IvanStoev
  • 您可以删除Cast 并简单地使用AsEnumerable&lt;ITestViewModel&gt;()。最终将得到我的答案的延迟版本:)
  • 同意这种做法。尊重不变性 == 更安全的代码。
【解决方案2】:

问题是query 变量类型是List&lt;DrugTestViewModel&gt;,而您需要它是List&lt;ITestViewModel&gt; 类型。由于IQueryable&lt;T&gt; 是协变的,您可以通过在像这样调用ToList 时简单地明确指定所需的类型来实现这一点

var query = (...).ToList<ITestViewModel>();

【讨论】:

  • 谢谢,@IvanStoev。在这种情况下,covariant 是什么意思?
  • 这意味着,你可以把IQueryable&lt;DerivedClass&gt;当作IQueryable&lt;BaseClassOrInterface&gt;
【解决方案3】:

上下文中的 from at... 是一个查询,因此 IQuerable 错误 在 linq 查询末尾添加 .ToList() 调用会返回一个支持 IEnumerable 的列表。

您的第一个代码 sn-p 包含您的第二个缺少的 .ToList()。

【讨论】:

  • 最好使用AsEnumerable 并避免创建中间列表。
  • 谢谢,@juharr。请参阅异常的更新。在第二个查询中,它不会给我ToList() 的选项;有.ToString() 但没有ToList()
  • @Alex 您是否在查询周围加了括号?
  • @juharr,是的,但它仍然不会显示 ToList()
  • @Alex,这真的没关系,因为真正的问题是queryDrugTestViewModel 的列表,您不能将AlcoholTestViewModel 添加到其中。试试 Ivan 的建议。
猜你喜欢
  • 2014-08-30
  • 1970-01-01
  • 2012-09-06
  • 2012-09-09
  • 1970-01-01
  • 2010-12-12
  • 1970-01-01
  • 1970-01-01
  • 2015-02-08
相关资源
最近更新 更多