【问题标题】:How can I get an one to one object without with only one related entities?如何在没有一个相关实体的情况下获得一对一的对象?
【发布时间】:2018-08-23 12:39:38
【问题描述】:

我有一个包含 InventoryItem 的 Book 类,而 InventoryItem 包含 Book,所以关系是一对一的。如果我想获取 Inventory 项目,它将返回包含该 InventoryItem 的 Book 等等。我想将该 InventoryItem 作为 IActionResult 返回。

图书课:

public string Title { get; set; }
public IEnumerable<Author> Authors { get; set; }
public Category Category { get; set; }
public string Isbn { get; set; }
public string PublishingHouse { get; set; }
public string Edition { get; set; }
public InventoryItem InventoryItem { get; set; }
public bool IsDamaged { get; set; }
public bool IsLost { get; set; }

InventoryItem 类:

public Guid BookId { get; set; }
public Book Book { get; set; }
public int Number { get; set; }
public AcquisitionDetail AcquisitionDetail { get; set; }

返回 InventoryItem 的方法:

public async Task<IEnumerable<InventoryItem>> GetInventoryItemsAsync()
{
    return await schoolLibraryContext.InventoryItems.Include(inventoryItem => inventoryItem.Book)
        .Include(inventoryItem => inventoryItem.AcquisitionDetail)
        .ToListAsync();
}

问题:当我想返回 InventoryItem 时,如何只包含一个没有 InventoryItem 的 Book 对象。

【问题讨论】:

  • 如果您使用它通过 API 返回,您可以创建一个 ViewModel 并使用 AutoMapper 来映射您想要呈现的属性?

标签: c# asp.net .net asp.net-mvc entity-framework


【解决方案1】:

我假设问题是关于实体框架的,因为它在标签中。

在应用内使用数据方面:

在这种情况下,您不必担心。除非您使用Include 专门询问它,否则Book 将被延迟加载,即在初始查询时不会发送它,如果您实际使用它,将发送另一个查询来检索它。

但要小心,延迟加载可以节省大量流量,但它也很容易导致“N+1”问题,即使您可以一次加载整个实体,您也会不断发送查询。因此,如果您后来碰巧实际使用了Book,最好使用Include 并在最初加载,与数据流量相比,执行查询相对昂贵。

就向外部发送此数据而言(通过 API)

永远不要将您的实体返回到外面。即使您真的想返回它的所有属性,这也是非常糟糕的做法。

如果将数据返回到外部,则应将其映射到其他类的对象,然后返回该类。这样你就可以确保你永远不会发送太多数据,例如通过使用您不想发送到外部的属性来扩展您的实体。

在你的情况下,它可能看起来像:

public class BookModel
{
    public string Title { get; set; }
    public IEnumerable<AuthorModel> Authors { get; set; }
    public Category Category { get; set; }
    public string Isbn { get; set; }
    public string PublishingHouse { get; set; }
    public string Edition { get; set; }
    public bool IsDamaged { get; set; }
    public bool IsLost { get; set; }
}

public class InventoryItemModel
{
    public Guid BookId { get; set; }
    public BookModel Book { get; set; }
    public int Number { get; set; }
    public AcquisitionDetailModel AcquisitionDetail { get; set; }
}

【讨论】:

  • 好的,谢谢您的回答。但是如果我使用延迟加载,我需要将对象属性设为虚拟,不是吗?我也尝试将实体映射到模型,但它不起作用,我得到了相同的对象,但是在模型中。或许,我有些不明白。
  • 看看我的回答中的sn-p。将实体映射到模型的原因之一是删除导航属性中的循环。在这种情况下,InventoryItemModel 包含对BookModel 的引用,但BookModel 不再包含对InventoryItemModel 的引用,因此如果您在通过 API 发送实体之前将其映射到此模型,您将只会获得一份 book , 而不是这个无限循环。
  • 是的,如果你想使用延迟加载,属性应该是虚拟的。将所有属性虚拟化是一种很好的做法,在从 Context 获取实体后立即将其映射到模型/DTO(数据传输对象,在大多数情况下,它与实体相同,除了它的属性不是虚拟的,而且它是不可变的,也就是说,属性仅在构造函数中设置,您进行更改,您创建新对象)并且将数据发送到外部意味着将 DTO 映射到 ViewModel,其中仅包含您要显示的数据。
  • 我建议您阅读有关 MVVM (Model-View-ViewModel) 的内容,然后您应该明白为什么将所有这些分开很重要。
  • 好的,谢谢。我会将您的答案标记为正确。那是我的错误,BookModel 不包含 InventoryItemModel。但我建议你看看这篇关于延迟加载的帖子:https://ardalis.com/avoid-lazy-loading-entities-in-asp-net-applications
猜你喜欢
  • 2019-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-01
  • 2011-03-16
  • 1970-01-01
  • 2018-10-28
相关资源
最近更新 更多