【问题标题】:Error when doing mulitple ProjectTo layers with EfCore使用 Ef Core 对图层执行多个项目时出错
【发布时间】:2019-12-10 14:47:21
【问题描述】:

我正在尝试创建一个“设计指南”,用于在我的公司中构建 rest api,我希望拥有一个包含 automapper、asp.net 核心和 ef 核心的 3 层结构。

Database Layer : DbSet Entities
Business Layer : Application Models
Api/Rest/External Layer : Dto Object

我已经通过以下要点成功地做到了这一点:https://gist.github.com/Angelinsky7/49c86333584e3f9cece44a88e7febd4e

但正如你所见,我需要使用 hack 来完成这项工作... (https://gist.github.com/Angelinsky7/49c86333584e3f9cece44a88e7febd4e#file-automapper_bug_lambda_projection-cs-L23-L24)、(https://gist.github.com/Angelinsky7/49c86333584e3f9cece44a88e7febd4e#file-automapper_bug_lambda_projection-cs-L89) 和 (https://gist.github.com/Angelinsky7/49c86333584e3f9cece44a88e7febd4e#file-automapper_bug_lambda_projection-cs-L93)

public IEnumerable<SubLayer2> _Subs { get; set; } = new HashSet<SubLayer2>();
public ICollection<SubLayer2> Subs => (ICollection<SubLayer2>)_Subs;

cfg.CreateMap<Layer1, Layer2>()
  .ForMember(p => p._Subs, opt => opt.MapFrom(src => src.Subs));
cfg.CreateMap<Layer2, Layer3>()
  .ForMember(p => p.Subs, opt => opt.MapFrom(src => src._Subs));

我非常不喜欢它(因为即使这样工作,在更复杂的 senarii 中,它也不再工作了)

如果我不这样做:https://gist.github.com/Angelinsky7/0e26507c07c066376d5a4de8726dd1f2

在 InMemory EfCore 案例中,Layer3 为 IEnumerable:(在创建问题之前我没有这个) Unhandled exception. System.InvalidOperationException: The LINQ expression 'dtoSubLayer2' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync()

在使用 Layer3 作为 IEnumerable 的 SqlServer EfCore 案例中:(我想使用什么) InvalidOperationException: When called from 'VisitLambda', rewriting a node of type 'System.Linq.Expressions.ParameterExpression' must return a non-null value of the same type. Alternatively, override 'VisitLambda' and change it to not visit children of this type.

在所有以 Layer3 作为 ICollection 的 EfCore 中: Unhandled exception. System.NullReferenceException: Object reference not set to an instance of an object.

我做错了什么?这完全不可能吗?有没有办法让我找到弹出异常并自定义此行为的 NullReferenceException 或 VisitLambda ?拥有这种解决方案将是完美的,因为我将拥有我想要构建我的 rest api 的东西......

来源/目的地类型

internal class Layer1 {
  public Int64 Id { get; set; }
  public ICollection<SubLayer1> Subs { get; set; } = new HashSet<SubLayer1>();
}

internal class SubLayer1 {
  public Int64 Id { get; set; }
  public Int64 LayerId { get; set; }
}

internal class Layer2 {
  public Int64 Id { get; set; }
  public ICollection<SubLayer2> Subs { get; set; } = new HashSet<SubLayer2>();
}

internal class SubLayer2 {
  public Int64 Id { get; set; }
}

internal class Layer3 {
  public Int64 Id { get; set; }
  public IEnumerable<SubLayer3> Subs { get; set; } = new HashSet<SubLayer3>();
}

internal class SubLayer3 {
  public Int64 Id { get; set; }
}

映射配置

cfg.CreateMap<Layer1, Layer2>();
cfg.CreateMap<SubLayer1, SubLayer2>();

cfg.CreateMap<Layer2, Layer3>();
cfg.CreateMap<SubLayer2, SubLayer3>();

版本:x.y.z

<PackageReference Include="AutoMapper" Version="9.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="3.1.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.1.0" />

预期行为

我应该能够多次使用 ProjectTo 来更改图层,而无需使用任何技巧。而且我应该能够在需要时在 ICollection 和 IEnumerable 之间进行选择

实际行为

根据实现之一,会出现 3 个异常(大多数情况下是 'VisitLambda' lambda 之一

重现步骤

https://gist.github.com/Angelinsky7/0e26507c07c066376d5a4de8726dd1f2

感谢所有的帮助,感谢您抽出宝贵的时间!!! (很抱歉,如果这是一个 efcore 问题,但我在想:“因为我可以在 automapper 中创建一个“hack”,它可能就在这里”)

我来到这里是因为 automapper 团队认为这不是他们的错误 (https://github.com/AutoMapper/AutoMapper/issues/3280)

【问题讨论】:

  • 您已经在以一种骇人听闻的方式使用 Automapper。它只是为了强制执行一些映射约定——仅此而已!在这种情况下,甚至不可能再看到发生了什么。由 Automapper 的创建者检查 Automapper's Design Philosohpy
  • 您的代码如此复杂,并且比执行简单的 LINQ 查询然后根据需要映射 DTO 复杂得多,这一事实应该是一个非常有力的指标,表明某些事情是错了
  • 看来问题出在我使用 IEnumerable 和 ICollection 并将数据从 ICollection 转换为 IEnumerable 是罪魁祸首。
  • @PanagiotisKanavos 我明白你的意思,但我不觉得我不尊重 Automapper 的哲学,而是使用 2 层 DTO .... 最后,我的目的是拥有简单的 LINQ查询(事实上,如果我根本不使用 IEnumerable,一切都非常顺利),但取决于“谁”调用服务,我不想给出相同的可能性......
  • 我不想通过这样做来限制查询的种类,我想在层实体之间映射我的模型 -> 模型 -> dtos 而不仅仅是实体 -> dtos

标签: c# asp.net-core automapper ef-core-3.0


【解决方案1】:

似乎 automapper 不能做我想做的事。 我的错。 感谢社区帮助我。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-11-20
    • 1970-01-01
    • 2021-09-15
    • 1970-01-01
    • 2020-10-07
    • 2021-03-26
    • 1970-01-01
    • 2021-06-28
    相关资源
    最近更新 更多