How to avoid circular navigation properties in Entity Framework Core?

谁说我不能喝 提交于 2020-01-06 03:42:46

问题


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:

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:

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:

How can I avoid circular navigation properties? Please, tell me what I've done wrong? Is it expected and correct behaviour?


回答1:


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

Moving away from Entity Framework for a moment, consider the generic collection class LinkedList, which is a chained collection of LinkedListNode objects. Each node has a Next and a Previous, while the list itself has a First and a Last (the linking is hence bidirectional)

If you put two items in your list, "hello" and "world" then examined it in the debugger you'd see:

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

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. 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



来源:https://stackoverflow.com/questions/58034555/how-to-avoid-circular-navigation-properties-in-entity-framework-core

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!