【问题标题】:Mapping EF Entities to ViewModels maintaining ICollection and lazy loading将 EF 实体映射到维护 ICollection 和延迟加载的 ViewModel
【发布时间】:2016-08-15 23:55:22
【问题描述】:

自从转向 EF 6 以来,这一直困扰着我。我们现在如何将集合映射到视图模型,以便使用 IEnumerables 映射更改不会很痛苦。下面是一个代码 sn-p,演示了我的问题:

实体 - SS.Entity.Event

[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<SS.Entity.User> Broadcasters { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<SS.Entity.User> Viewers { get; set; }

模型 - SS.Model.Event

public virtual ICollection<SS.Model.User> Broadcasters { get; set; }
public virtual ICollection<SS.Model.User> Viewers { get; set; }

集合修改后映射回实体

Broadcasters = e.Broadcasters.Select(u => new SS.Entity.User
{
    Id = u.Id,
    SkypeId = u.SkypeId,
    Name = u.Name
}).ToList(), // THIS IS THE PROBLEM
Viewers = e.Viewers.Select(u => new SS.Entity.User
{
    Id = u.Id,
    SkypeId = u.SkypeId,
    Name = u.Name
}).ToList() // THIS IS THE PROBLEM

这个问题是我不能将一个 ICollection 映射到另一个 ICollection,因为 Select 会产生一个 IEnumerable,这使得在之后将属性映射回 EF 变得很痛苦,因为我必须重新创建集合或枚举它来更新它。我知道我遗漏了一些明显的东西,我已将 ICollection 更新为虚拟的,如其他答案中所述,但我不清楚这有什么帮助。

任何帮助将不胜感激!

杰拉德

【问题讨论】:

  • 为什么不Broadcasters = e.Broadcasters?很不清楚你在问什么。有一个User 类,还是两个?延迟加载与此有何关系?
  • 我试图通过添加命名空间使其更清晰。本质上,我的问题是如何在 EF6 中映射回集合更改。如果没有 ToList(),我看不到明确的方法可以做到这一点。因此,在处理大型集合时会严重影响性能。
  • "....将集合映射到视图模型,以便使用 IEnumerables 映射更改不会很痛苦".....这不清楚。 “地图收藏通过”是什么意思。如您的帖子所示,您正在从您的 DTO 创建新类型.....为什么这对您不起作用?
  • 您是否正确构建了视图模型?您可以使用这种方法大大简化它们:stackoverflow.com/questions/11064316/what-is-viewmodel-in-mvc/…
  • 我不明白您希望如何在没有枚举的情况下执行转换(一种用户类型到另一种)。唯一的“挑战”是确保您只枚举一次。也许您不应该将大型收藏品带入客户。客户应该如何处理它们?

标签: c# entity-framework repository-pattern


【解决方案1】:

假设您的“.ToList()”问题是在保存回数据库时,这是您要寻找的吗?:

 var event = new SS.Entity.Event {Name = "New Name" and other properties};

 IEnumerable<SS.Entity.User> broadcasters = e.Broadcasters
        .Select(u => new SS.Entity.User
             {
              Id = u.Id,
              SkypeId = u.SkypeId,
              Name = u.Name
           });

 var viewers = e.Viewers.Select(u =>
          new SS.Entity.User
          {
             Id = u.Id,
             SkypeId = u.SkypeId,
              Name = u.Name
          });

 //add broadcasters to event
 event.Broadcasters.AddRange(broadcasters);

 //add viewers to event
 event.Viewers.AddRange(viewers);

 dataContext.Events.Add(event);
 dataContext.SaveChanges();

【讨论】:

  • 这是个好主意...我目前无法访问代码来试用它,但让我明天看看。添加范围是否需要 IEnumerable?
  • @Gerard - 是的,确实如此。 msdn.microsoft.com/en-us/library/…
  • @GerardWilkinson 运气好吗?
  • 我还没有机会。我会给你赏金,因为我认为这是一个很好的解决方案!
【解决方案2】:

在您的 ViewModel 上,它们只能是 IEnumerable&lt;T&gt;,除非您稍后需要对它们执行 .Add()。那可以是你想成为的任何人。此外,它们不必在模型上是虚拟的,因为您没有让 EF 创建模型的派生类型(同样,除非您有其他理由)。

要将它们设置回它们在 DTO 对象中的状态,如果您只想直接设置它而不检查单个属性,则可以使用 .ToList() 使其满足 ICollection&lt;T&gt; 要求。

// Assuming "var model" is coming in as a parameter
var station = context.Viewers.First();
station.Broadcasters = model.Broadcasters.Select(b => new User {
    Id = b.Id,
    SkypeId = b.SkypeId,
    Name = b.Name
}).ToList();
station.Viewers = model.Viewers.Select(v => new User {
    Id = v.Id,
    SkypeId = v.SkypeId,
    Name = v.Name
});

【讨论】:

  • 这曾经在 EF6 之前的版本中工作,但不再工作。实例化新实体甚至用于映射回导致为每次更新创建新实体,而不仅仅是更新集合。
  • ToList() 还会枚举集合,如果该集合很大,则会导致性能问题。
  • 无论如何,集合都会被迭代。至少,您的问题非常不清楚您的问题集是什么。 EF5 中没有发生的 EF6 现在发生了什么?
  • 如果您有对象集的 ID,并且属性设置为 DatabaseGeneratedOption.Identity,那么无论您的实体的跟踪状态如何,它都会运行 UPDATE 而不是 INSERT。
  • 我已经有一段时间没有研究实体框架了。但是据我所知,我曾经能够在没有 ToList 的情况下映射集合更改。我不一定要遍历集合。例如,如果我只是将一个用户删除或添加到 Viewer 或 Broadcaster 集合中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多