【问题标题】:How to avoid circular navigation properties in Entity Framework Core?如何避免 Entity Framework Core 中的循环导航属性?
【发布时间】:2020-01-21 21:03:58
【问题描述】:

我有一个这样的表架构:

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 生成以下代码:

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; }        
}

还有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");
    });
}

我写了以下代码:

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

我有以下循环导航属性,这些属性将被创建,直到我点击Products

如何避免循环导航属性?请告诉我我做错了什么?这是预期的正确行为吗?

【问题讨论】:

  • 你不能,但你不需要——这没有错。 EF 也会把它们牢记在心
  • @CaiusJard 你的意思是这是正确的和预期的行为吗?
  • 其实这和Entity Framework没有关系。这发生在任何引用其所有者的 C# 元素集合中,并且它应该发生。调试器不会创建新属性。它只是一次又一次地显示相同的产品和类别。
  • @GertArnold 随意回答,我会将其标记为答案!非常感谢!祝你有美好的一天!:)

标签: c# tsql asp.net-core entity-framework-core


【解决方案1】:

这是任何编程语言的预期部分,因为总是可以创建相互引用的对象。当对此进行可视化时,Visual Studio 中的调试器将仅显示链接,以响应您对对象树的导航

暂时离开实体框架,考虑通用集合类 LinkedList,它是 LinkedListNode 对象的链式集合。每个节点都有一个 Next 和一个 Previous,而列表本身有一个 First 和一个 Last(因此链接是双向的)

如果您在列表中放入两个项目,“hello”和“world”,然后在调试器中检查它,您会看到:

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

您可以整天来回走动,使调试器可视化器中的树越来越深。这不是错误或问题,它只是用代码编写的概念视觉等价物:

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

您也可以整天交替输入 Next 和 Previous - 这是有效的 C#,但可能没有必要,除非您正在走一棵分叉的树,并且您想在沿着不同的分支前行之前更靠近根部

这种“循环”结构会在一个对象引用另一个引用原始对象的对象的任何地方弹出 - DataTable 的 DataRows 每个都有一个 .Table 属性,该属性引用回拥有该行的表,依此类推。没问题,也不会导致您的代码在无限循环中崩溃 - EF 不会尝试保存客户,然后是客户的订单,然后是客户订单的客户,然后是客户订单的客户订单.. . 等等。它知道何时停止保存客户订单对

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-11-09
    • 2023-03-17
    • 1970-01-01
    • 2021-05-27
    • 2017-01-01
    • 2021-05-17
    • 1970-01-01
    • 2018-10-10
    相关资源
    最近更新 更多