【问题标题】:Prevent AutoMapper Projections From Forcing Related Data Loading防止 AutoMapper 投影强制相关数据加载
【发布时间】:2016-11-14 11:13:54
【问题描述】:

有没有办法配置 AutoMapper 以遵守 .Include 实体框架的样式加载说明?

我已为我的上下文禁用延迟加载,我想有条件地加载特定实体的相关数据。理想情况下,我想通过使用包含语法来做到这一点。比如:

if(loadAddreses)
{
    query = query.Include(e => e.Addresses);
}

if(loadEmails)
{
    query = query.Include(e => e.Emails);
}

问题是,AutoMapper 看到我要投影的模型包括地址和电子邮件,并且正在生成加载所有数据的 SQL,而不管我要求 EF 包括什么。换句话说:

var model = query.Project.To<MyModel>();

如果 MyModel 有一个 Addresses 集合,它将加载地址,而不管我的 Include 语句。

没有改变我的模型,让我有一个没有地址或电子邮件属性的模型,有没有办法解决这个问题?我想我可以更改我的映射,但映射通常是静态的,并且在最初创建后不会更改。

【问题讨论】:

  • 对于您正在处理的每个场景都有不同的映射怎么样?我意识到这可能并不理想,但 Automapper 将根据您的投影生成表达式树,因此如果您不忽略某些内容,它将包含在数据库查询中。
  • 这用于通用查询对象模式,我称之为查询规范模式。这个问题的主要目标是看看我是否可以让模式“更安全”。
  • “更安全”,您的意思是要避免Automapper加载您不想加载的相关集合的情况吗?
  • 是的。我想允许投影,但只允许那些是我选择公开的数据子集的那些。
  • 所以回到我原来的评论,您是否愿意接受使用多个映射的建议,以便您可以涵盖每个场景?

标签: entity-framework automapper


【解决方案1】:

这有点棘手,但看看这对你有什么作用。请注意,我使用的是 AutoMapper 3.3.0-ci1027 版本(在撰写本文时这是一个预发布版本)。

假设我的数据模型如下所示:

public class Address
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int AddressId { get; set; }
    public string Text { get; set; }
}

public class Email
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int EmailId { get; set; }
    public string Text { get; set; }
}

public class User
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int UserId { get; set; }
    public virtual ICollection<Address> Addresses { get; set; }
    public virtual ICollection<Email> Emails { get; set; }

    public User()
    {
        this.Addresses = new List<Address>();
        this.Emails = new List<Email>();
    }
}

我的视图模型没有指定,但它们只包含与实体相同的属性。

我从UserUserViewModel 的映射如下所示:

Mapper.CreateMap<User, UserViewModel>()
    .ForMember(x => x.Emails, opt => opt.ExplicitExpansion())
    .ForMember(x => x.Addresses, opt => opt.ExplicitExpansion());

我的投影是这样的:

var viewModels = context.Set<User>().Project()
    .To<UserViewModel>(new { }, u => u.Emails).ToList();

使用该映射和投影,仅加载 Emails 集合。对此的重要部分是映射中的 opt =&gt; opt.ExplicitExpansion() 调用 - 除非在投影期间显式扩展,否则它会阻止遵循导航属性,以及重载的 To 方法。此重载允许您指定参数(我将其保留为空对象)以及您希望扩展的成员(在本例中为 Emails)。

在这个阶段我不确定的一件事是从Include 语句中提取详细信息的精确机制,以便您可以将它们依次传递给To 方法,但希望这能给您一些帮助一起工作。

【讨论】:

  • 你为什么要使用 Set?.. 就我而言,它只是通过禁用延迟加载、配置显式扩展的映射和执行 dc.User.Include("Emails").Project() 来工作。到().
  • @TheZenCoder 在这种情况下,使用 Set 没有任何区别。您确定该代码有效吗?我的理解是 To 方法生成 Select 语句。
  • 是的,它有效。我今天早些时候在我的盒子上用 3.3.0-ci1027 版本的 automapper 进行了尝试。
  • 这正是我所需要的。好东西!谢谢!
猜你喜欢
  • 2019-07-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多