【问题标题】:EF Core ToDictionary throw expression could not be translatedEF Core ToDictionary throw 表达式无法翻译
【发布时间】:2021-10-20 12:12:34
【问题描述】:

我有这个问题:

        Project = await Context.Projects.Where(x => x.Id == project.Id)
        .Select(x => new ProjectModel
        {
            Id = project.Id,
            Name = project.Name,                
            TreeDataDict = x.Tasks.Select(y => new TreeItemModel()
            {
                NodeId = y.Id,
                ParentId = SetTaskParentId(y, y.Type),
                NodeTitle = y.Name,
                Expanded = false,
                Object = new TaskBaseModel
                {
                    Milestone = y.Milestone,
                    StartDate = y.StartDate,
                    CurrentEndDate = y.CurrentEndDate,
                    EndDate = y.EndDate,
                },
                Icon = TaskHelper.GetTaskIcon(y.Type),
                Children = new List<TreeItemModel>()
            }).ToDictionary(y => y.NodeId, y => y)                              
        }).SingleOrDefaultAsync();

也试过这样:

        Project = await Context.Projects.Where(x => x.Id == project.Id)
        .Select(x => new ProjectModel
        {
            Id = project.Id,
            Name = project.Name,                
            TreeDataDict = x.Tasks.ToDictionary(y => y.Id, y => new TreeItemModel(
            {
                NodeId = y.Id,
                ParentId = SetTaskParentId(y, y.Type),
                NodeTitle = y.Name,
                Expanded = false,
                Object = new TaskBaseModel
                {
                    Milestone = y.Milestone,
                    StartDate = y.StartDate,
                    CurrentEndDate = y.CurrentEndDate,
                    EndDate = y.EndDate,
                },
                Icon = TaskHelper.GetTaskIcon(y.Type),
                Children = new List<TreeItemModel>()
            })                              
        }).SingleOrDefaultAsync();

我得到这个异常的两种方式:

这可能是什么原因造成的?有没有一种方法可以在不作为列表获取然后将其转换为字典的情况下完成这项工作?实现这一目标的最有效方法是什么?

问候

【问题讨论】:

  • 我认为首先获取列表然后将 ist 转换为字典没有有用的方法。异常告诉您的是,EF 无法将您编写的查询转换为 SQL,这是有道理的,因为 Dictionary 是 SQL 中不存在的 .NET 类型。

标签: linq dictionary entity-framework-core


【解决方案1】:

这可能是什么原因造成的?

不支持翻译嵌套的ToDictionary 调用(没有可用的重载)。将其视为(许多)当前(在编写官方 v5.0.11 时最新的)EF Core 缺点之一。

有趣的是,Dictionary&lt;TKey, TValue&gt; 构造函数重载带有 IEnumerable&lt;KeyValuePair&lt;TKey, TValue&gt;&gt; 参数以及投影 (Select) 到 KeyValuePair&lt;TKey, TValue&gt; 支持的,这提供了解决方法 - 替换 ToDictionary使用上述构造函数和Select 调用,例如(将int替换为Id的类型)

TreeDataDict = new Dictionary<int, TreeItemModel>(
x.Tasks.Select(y => new TreeItemModel()
{
    NodeId = y.Id,
    ParentId = SetTaskParentId(y, y.Type),
    NodeTitle = y.Name,
    Expanded = false,
    Object = new TaskBaseModel
    {
        Milestone = y.Milestone,
        StartDate = y.StartDate,
        CurrentEndDate = y.CurrentEndDate,
        EndDate = y.EndDate,
    },
    Icon = TaskHelper.GetTaskIcon(y.Type),
    Children = new List<TreeItemModel>()
})
.Select(e => new KeyValuePair<int, TreeItemModel>(e.NodeId, e)));

这将修复当前错误。但请注意,您正在使用仅在最终 Select 中支持的其他不可翻译构造(自定义方法调用,如 SetTaskParentId(y, y.Type)TaskHelper.GetTaskIcon(y.Type)),因此请确保添加 LINQ 运算符如WhereOrderBy 等在根查询Select(x =&gt; new ProjectModel { ... } 之后,否则会出现其他运行时错误。 ToList, `第一

【讨论】:

  • 谢谢你这对我有用,想知道是否有一种方法只有一个 Select..
  • 当然,你可以修改你原来的选择,直接y =&gt; new KeyValuePair&lt;...&gt;(y.Id, new TreeItemModel() { ... }))。但我这样做是为了让它更接近原始构造。当 LINQ 查询被转换为 SQL 时,多个 LINQ 选择并不重要,因为翻译器会将它们合并为单一选择(正如您在生成的 SQL 中看到的那样)。
  • 感谢您的帮助
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-09-10
  • 2022-11-11
  • 2022-11-11
  • 1970-01-01
  • 2021-10-24
  • 2021-12-25
  • 1970-01-01
相关资源
最近更新 更多