简体   繁体   English

如何避免 Entity Framework Core 中的循环导航属性?

[英]How to avoid circular navigation properties in Entity Framework Core?

I have a such table schema:我有一个这样的表模式:

CREATE TABLE Categories
(
    Id INT IDENTITY(1,1),
    Name varchar(100),
    CONSTRAINT PK_Category_Id PRIMARY KEY (Id)
)

CREATE TABLE Products
(
    Id INT IDENTITY(1,1),
    IdCategory INT NOT NULL
        CONSTRAINT FK_Products_IdCategory__Categories_Id FOREIGN KEY(IdCategory) REFERENCES Categories(Id),
    Name varchar(100), 
    Price decimal(18,2),
    ImageUrl varchar(256),
    CONSTRAINT PK_Product_Id PRIMARY KEY (Id)
)

EF Core generated the following code: EF Core 生成了以下代码:

public partial class Categories
{
    public Categories()
    {
        Products = new HashSet<Products>();
    }

    public int Id { get; set; }
    public string Name { get; set; }

    public virtual ICollection<Products> Products { get; set; }
}

public partial class Products
{
    public Products()
    {
        OrderItems = new HashSet<OrderItems>();
        ShoppingCartItems = new HashSet<ShoppingCartItems>();
    }

    public int Id { get; set; }
    public int IdCategory { get; set; }
    public string Name { get; set; }
    public decimal? Price { get; set; }
    public string ImageUrl { get; set; }

    public virtual Categories IdCategoryNavigation { get; set; }
    public virtual ICollection<Items> Items { get; set; }        
}

And OnModelCreating(ModelBuilder modelBuilder) method:OnModelCreating(ModelBuilder modelBuilder)方法:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.HasAnnotation("ProductVersion", "2.2.6-servicing-10079");

    modelBuilder.Entity<Categories>(entity =>
    {
        entity.Property(e => e.Name)
            .HasMaxLength(100)
            .IsUnicode(false);
    });

    modelBuilder.Entity<Products>(entity =>
    {
        entity.Property(e => e.ImageUrl)
            .HasMaxLength(256)
            .IsUnicode(false);

        entity.Property(e => e.Name)
            .HasMaxLength(100)
            .IsUnicode(false);

        entity.Property(e => e.Price).HasColumnType("decimal(18, 2)");

        entity.HasOne(d => d.IdCategoryNavigation)
            .WithMany(p => p.Products)
            .HasForeignKey(d => d.IdCategory)
            .OnDelete(DeleteBehavior.ClientSetNull)
            .HasConstraintName("FK_Products_IdCategory__Categories_Id");
    });
}

I've written the following code:我编写了以下代码:

public override async Task<Products> GetById(int id)
{   
    return await DbContext.Products
        .Include(p => p.IdCategoryNavigation)
        .FirstOrDefaultAsync(p => p.Id == id);
}

And I've got the following circular navigation properties and these properties will be created until I click on Products :而且我有以下循环导航属性,这些属性将被创建,直到我点击Products 在此处输入图像描述

How can I avoid circular navigation properties?如何避免循环导航属性? Please, tell me what I've done wrong?请告诉我我做错了什么? Is it expected and correct behaviour?这是预期的和正确的行为吗?

This is an expected part of any programming language because it's always possible to create objects that refer to each other.这是任何编程语言的预期部分,因为总是可以创建相互引用的对象。 When visualising this the debugger In visual studio will just show the links as it sees it in response to your navigation of the object tree当对此进行可视化时,Visual Studio 中的调试器将仅显示链接,以响应您对 object 树的导航

Moving away from Entity Framework for a moment, consider the generic collection class LinkedList, which is a chained collection of LinkedListNode objects.暂时离开实体框架,考虑通用集合 class LinkedList,它是 LinkedListNode 对象的链式集合。 Each node has a Next and a Previous, while the list itself has a First and a Last (the linking is hence bidirectional)每个节点都有一个 Next 和一个 Previous,而列表本身有一个 First 和一个 Last(因此链接是双向的)

If you put two items in your list, "hello" and "world" then examined it in the debugger you'd see:如果您在列表中放入两个项目,“hello”和“world”,然后在调试器中检查它,您会看到:

list.First          LinkedListNode "hello"
  .Next             LinkedListNode "world"
    .Previous       LinkedListNode "hello"
      .Next         LinkedListNode "world"

You could step back and forth all day, making the tree in the debugger visualiser deeper and deeper.您可以整天来回走动,使调试器可视化器中的树越来越深。 It's not an error or a problem, it's just the conceptual visual equivalent of writing in code:这不是错误或问题,它只是用代码编写的概念视觉等价物:

list.First.Next.Previous.Next; //"world

You could alternate typing Next and Previous all day too - it's valid C# though probably unnecessary unless you're walking a tree that branches out and you want to go up closer to the root before travelling down a different branch您也可以整天交替输入 Next 和 Previous - 它是有效的 C# 虽然可能没有必要,除非您正在走一棵分叉的树并且您想要 go 靠近根部,然后再沿着不同的分支行进

This "cyclical" structure pops up anywhere an object refers to another object that refers to the original - A DataTable's DataRows each have a.Table property that refers back to the table that owns the row and so on.这种“循环”结构会在 object 引用另一个 object 的任何地方弹出,该 object 引用原始数据 - DataTable 的 DataRows 每个都有一个 .Table 属性,该属性引用回拥有该行的表等等。 Not a problem and won't cause your code to break down in some endless loop - EF won't try to save the Customers, then the Customer's Orders, then the Customer's Orders' Customers, then the Customer's Orders' Customers' Orders... etc. It knows when to stop saving a Customer Order pair没问题,也不会导致您的代码在无限循环中崩溃 - EF 不会尝试保存客户,然后是客户的订单,然后是客户订单的客户,然后是客户订单的客户订单。 . 等等 它知道何时停止保存客户订单对

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM