繁体   English   中英

实体框架(核心),多次引用同一张表但对象不同

[英]Entity Framework (Core), multiple refrences to the same table but different objects

我有一个汽车零件:

CREATE TABLE dbo.Part (
    Id int IDENTITY(1,1) not null,
    PartNumber nvarchar(48) not null,
    Colour nvarchar(100) null,
    Height int null,
    -- etc
)

汽车零件通常是可互换的。 您可以将汽车/卡车上的1个零件替换为OEM零件“ A”或配件市场零件“ B”。

CREATE TABLE dbo.Interchanges (
    Part1 int not null,
    Part2 int not null,
    Notes nvarchar(500) not null,
)

ALTER TABLE dbo.Interchanges WITH CHECK ADD CONSTRAINT fk_Interchanges_Part1
FOREIGN KEY (Part1) REFERENCES dbo.Part (Id)

ALTER TABLE dbo.Interchanges WITH CHECK ADD CONSTRAINT fk_Interchanges_Part2
FOREIGN KEY (Part2) REFERENCES dbo.Part (Id)

注意:1个部分可以与许多其他部分互换,在这种情况下,互换是双向的。

现在,假设我有两个部分(零件号A和B),并且它们彼此互换。

当我实例化A部分时,我希望它具有一组Interchanges。 在这种情况下,集合将只有一个对象。 该对象将具有交换注释和零件编号为B的零件对象实例。

同样,如果我编辑零件B,则其集合中将有一个对象,该对象具有互换注释和零件实例,零件编号为A。

有没有一种优雅的方式对此建模?

Google可以为这种模式命名吗?

使用上面的SQL,当我加载部件A时,它具有一个ICollection(使用Entity Framework Power Tools插件创建)。 该交换对象具有交换注释,B部分的实例以及A部分的实例。

在关系模型中,没有一流的方法来为对称关系建模,因此您要么必须在应用程序代码中对其进行处理,要么将其存储为两个单独的行(A,B,“ A和B可互换”)和(B ,A,“ A和B可互换”)

如果为每个关系的倒数添加行,则EF模型很简单,因为零件仅需要一个导航属性。

这是您正在寻找的代码优先模型版本:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Linq;

namespace ConsoleApp6
{
    public class Part
    {
        public int Id { get; set; }
        public string PartNumber { get; set; }
        public string Colour { get; set; }
        public int Height { get; set; }

        public virtual ICollection<Interchange> Interchanges { get; } = new HashSet<Interchange>();

    }

    public class Interchange
    {
        [Key]
        [Column(Order =1 )]
        public int FromPartId { get; set; }

        [Key]
        [Column(Order = 2)]
        public int ToPartId { get; set; }

        public virtual Part FromPart { get; set; }
        public virtual Part ToPart { get; set; }
    }



    class Db : DbContext
    {

        public DbSet<Part> Parts { get; set; }
        public DbSet<Interchange> Interchanges { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Part>()
                        .HasMany(p => p.Interchanges)
                        .WithRequired()
                        .HasForeignKey(i => i.FromPartId)
                        .WillCascadeOnDelete(false);

            base.OnModelCreating(modelBuilder);
        }


    }
    class Program
    {
        static void Main(string[] args)
        {
            Database.SetInitializer(new DropCreateDatabaseAlways<Db>());

            using (var db = new Db())
            {
                db.Database.Log = a => Console.WriteLine(a);

                var A = db.Parts.Create();
                A.PartNumber = "A";

                var B = db.Parts.Create();
                B.PartNumber = "B";

                A.Interchanges.Add(new Interchange() {  FromPart = A, ToPart = B });
                B.Interchanges.Add(new Interchange() { FromPart = B, ToPart = A });

                db.Parts.Add(A);
                db.Parts.Add(B);

                db.SaveChanges();
            }

            using (var db = new Db())
            {
                db.Configuration.LazyLoadingEnabled = true;
                db.Configuration.ProxyCreationEnabled = true;

                var A = db.Parts.Where(p => p.PartNumber == "A").Single();

                Console.WriteLine($"Part {A.PartNumber} has {A.Interchanges.Count()} Interchanges");

                Console.WriteLine($"Part {A.PartNumber} is interchangable with {A.Interchanges.First().ToPart.PartNumber}");
            }
                Console.ReadKey();
        }
    }
}

暂无
暂无

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

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