gpt4 book ai didi

c# - AutoMapper ProjectTo 继承问题

转载 作者:行者123 更新时间:2023-11-30 14:23:57 25 4
gpt4 key购买 nike

如何使 ProjectTo 正确映射不同的派生类型而不将它们强制转换为基本类型?

这适用于 Mapper.Map,但不适用于 ProjectTo。

源类:(EntityFramework 模型)

public class FailureAlertEntity : AlertEntity
{
public FailureAlertEntity(int id, string description) : base(id)
{
Description = description;
}

public string Description { get; set; }
}

public class AlertEntity
{
public AlertEntity(int id)
{
ID = id;
}

public int ID { get; set; }
}

目标类(DTO 模型):

public class FailureAlert : Alert
{
public FailureAlert(int id, string description) : base(id)
{
Description = description;
}

public string Description { get; set; }
}

public class Alert
{
public Alert(int id)
{
ID = id;
}

public int ID { get; set; }
}

有多个类从 AlertEntity 和 Alert 派生,我想在这两种类型之间进行映射,而不会将派生类型转换为它们的基类型。

配置:

Mapper.Initialize(cfg => {
cfg.CreateMap<AlertEntity, Alert>()
.Include<FailureAlertEntity, FailureAlert>();
cfg.CreateMap<FailureAlertEntity, FailureAlert>();
});

测试代码:

var entities = new List<AlertEntity>()
{
new FailureAlertEntity(1, "foo"),
new FailureAlertEntity(2, "bar")
};

var alerts = entities.AsQueryable().ProjectTo<Alert>();

结果:

nope

ProjectTo 似乎没有考虑列表中项目的类型,而是将它们强制转换为列表本身的类型。如果列表的类型是 FailureAlertEntity,那么显然它会起作用,但列表可以包含从 AlertEntity 派生的其他类型。

如果我想使用 Mapper.Map 对一个对象做同样的事情,它工作得很好:

var faEntity = new FailureAlertEntity(1, "asd");
var dto = Mapper.Map<Alert>(faEntity);

结果:

yep

如何使 ProjectTo 映射类型像 Mapper.Map 那样?我假设他们都使用相同的配置。

最佳答案

你不能那样做,但这是有充分理由的。 ProjectToIQueryable 的扩展,而不是 IEnumerable。什么是 IQueryable

Provides functionality to evaluate queries against a specific data source

The IQueryable interface is intended for implementation by query providers.

因此 IQueryable 表示通过查询提供程序(如 Entity Framework)对数据源(如 sql server 数据库)的查询。 ProjectTo 将构建一个Select expression,它实际上不会在内存中投影任何内容。所以它会粗鲁地做这个:

entities.AsQueryable().Select(c => new Alert() {Property = c.Property})

Select 中的内容是表达式(不是函数),它将由查询提供程序转换为数据源查询(如 SELECT Property from ... 到 sql服务器)。此时,查询未执行,甚至无法知道它将返回哪些子类型(如果有)的元素。您只能选择列的一个子集,您不能说“如果 Alert 是 FailureAlert,请给我这个列,如果是 AnotherAlert,请给我另一个列”,这样的表达式无法转换为数据存储查询。现在,例如, Entity Framework 可以处理它的实体的继承(例如每个类型的表继承),但此时它比自动映射器有更多的信息(例如,哪些表用于处理继承)。 Automapper 只有映射源类型和映射目标类型。

鉴于上述情况 - AutoMapper 不可能以另一种方式进行。

现在,在您的示例中,您使用的是“假”IQueryable。如果在实际应用中是这种情况 - 只需使用 IEnumerable 和:

var alerts = Mapper.Map<List<Alert>>(entities);

var alerts = entities.Select(Mapper.Map<Alert>).ToList();

如果您有真正的 IQueryable,例如 Entity Framework 查询可以真正返回带有子类型的 AlertEntity 列表 - 您必须在使用 automapper 映射它之前具体化您的查询(当然,这将具体化具有所有属性的实体):

var alerts = yourQuery.AsEnumerable().Select(Mapper.Map<Alert>).ToList();

关于c# - AutoMapper ProjectTo 继承问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43113400/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com