【问题标题】:EF Core Many to many with same classEF Core 多对多同类
【发布时间】:2018-12-07 18:16:23
【问题描述】:

我有 City 类代表 City 及其邮政编码。我还有一个 Route 类,代表两个城市之间的巴士路线。所以,我希望在我的 Route 类中拥有 cityFrom 和 cityTwo 属性,两者都具有 City 类型 - 涉及同一类的多对多关系。

如何首先使用 EF Core 代码实现这一点?

谢谢!

更新:

我的模型看起来像这样:

public class Route
{
    public int Id { get; set; }

    public City CityFrom { get; set; }

    public City CityTo { get; set; }
}  
public class City
{
    public int Id { get; set; }

    public int PostCode { get; set; }

    public string Name { get; set; }
} 

这能解决我的问题吗:

        modelBuilder.Entity<Route>()
            .HasOne(f => f.CityFrom)
            .WithMany()
            .HasForeignKey(f => f.CityFromId);

        modelBuilder.Entity<Route>()
            .HasOne(f => f.CityTo)
            .WithMany()
            .HasForeignKey(f => f.CityToId);

还要在 Route 模型中添加 int 属性 CityFromId 和 CityToId?

【问题讨论】:

  • Route 类中需要将 ForeignKey 属性与 cityFrom 和 cityTo 一起使用。
  • 好的,但是这种情况下的语法会是什么样子?
  • 你能和我们分享你的模型吗?
  • 刚刚更新了问题,希望现在清楚...
  • 您提出的解决方案是解决问题的一种方法。或者,您可以使用ForeignKey 属性,即[ForeignKey(nameof(CityFrom))] public int CityFromId { get; set; }

标签: asp.net-core .net-core ef-code-first ef-core-2.0


【解决方案1】:

您可以在 ASP.NET Core 中使用 Data Annotations 实现多对多关系

根据您的要求,我们可以在CityRoute 之间引入一个名为CityRoute 的新类,它代表many-to-many

public class Route
{
    public int RouteId { get; set; } // change to make it more specific id
    public string CityFrom { get; set; }
    public string CityTo { get; set; }
    public ICollection<CityRoute> CityRoutes { get; set; }
}  

public class City
{
    public int CityId { get; set; } // change to make it more specific id
    public int PostCode { get; set; }
    public string Name { get; set; }
    public ICollection<CityRoute> CityRoutes { get; set; }
}

// new class
public class CityRoute 
{
    public City City { get; set; }
    public int CityId { get; set; }
    public Route Route { get; set; }
    public int RouteId { get; set; }
}

你的DataAnnotations可以是这样的

modelBuilder.Entity<CityRoute>()
        .HasKey(cr => new {cr.CityId, cr.RouteId});

希望对你有帮助

【讨论】:

  • 如果您需要识别路线或排序上的“端点”(开始/结束),那么 CityRoute 将是您在 IMO 中找到该信息的位置。 CityFrom/CityTo 是静态的,不可扩展。推理是依赖于连接键(路线+城市)的信息应该在连接表中。
  • 谢谢,这是更好、更灵活的解决方案!
  • @mark333...333...333 你的意思是公共字符串 CityFrom { get;放; } 和公共字符串 CityTo { get;放; } 应该是字符串还是城市类型?
【解决方案2】:

我不会设计这是一个多对多的关系。

每条路线都只有一个 FromCity,由外键 FromCityId 定义。
每条路线都只有一个 ToCity,由外键 ToCityId 定义。

public class Route
{
    public int Id { get; set; }

    // Every Route has one starting City defined by foreign key:
    public int FromCityId { get; set; }
    public virtual City FromCity { get; set; }

    // Every Route has one termination city, defined by foreign key
    public virtual int ToCityId { get; set; }
    public virtual City ToCity { get; set; }

    ...
}

还有 DbContext:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    // Proper name for table of Cities
    ModelBuilder.Entity<City>().ToTable("Cities");

    // Every Route has one required starting point defined by foreign key
    // Several routes may use the same City Id
    modelBuilder.Entity<Route>()
        .HasRequired(route => route.FromCity)
        .WithMany()
        .HasForeignKey(route => route.FromCityId)
        .WillCascadeOnDelete(false);

    // Every Route has one required termination point defined by foreign key
    // Several routes may use the same City Id
    modelBuilder.Entity<Route>()
        .HasRequired(route => route.ToCity)
        .WithMany()
        .HasForeignKey(route => route.ToCityId)
        .WillCascadeOnDelete(false);

    base.OnModelCreating(modelBuilder);

如果您删除一条路线,那么您不希望删除它们的城市,因为它们可能被其他路线使用:因此我们不希望在删除时级联 CascadeOnDelete(false)

【讨论】:

    【解决方案3】:

    EFCore 3。 需要自己的多对多类。

    我的问题是:人与人之间的关系(n->m)

    我的解决方案。 创建一个实现多对多的关系类。 我为班级中的记录选择了拥有自己的 ID。 所以关系类有 1 个 PK 和 2 个 FK(都属于 Person 类)。

    public class Person
    {
        public int ID { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public List<Relationship> MyRelationships { get; set; }
        public List<Relationship> TheirRelationships { get; set; }
    }
    

    //我添加为关系的人的MyRelationships。 //将我添加为关系的人的他们的关系。

    public class Relationship {
        public int RelationshipID { get; set; }
    
        public DateTime Since { get; set; }
        //ref to person myrelationships
        public int MyID { get; set; }
        public Person Me { get; set; }
    
        //ref to person theirrelationships
        public int TheirID { get; set; }
        public Person They { get; set; }
    }
    

    使用 add-migration 和 update-database 我了解到,在这种特殊情况下,EFCore 无法解析哪个 FK 用于哪个关系。 我使用 fluent API 解决了这个问题。

    public class ApplicationDbContext : IdentityDbContext
    {
    
        public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
            : base(options)
        {
        }
    
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
    
            //Write Fluent API configurations here
    
            modelBuilder.Entity<Person>()
                .HasMany<Relationship>(mr => mr.MyRelationships)
                .WithOne(p => p.Me)
                .HasForeignKey(m => m.MyID)
                .OnDelete(DeleteBehavior.NoAction);
    
            modelBuilder.Entity<Person>()
                .HasMany<Relationship>(tr => tr.TheirRelationships)
                .WithOne(p => p.They)
                .HasForeignKey(t => t.TheirID)
                .OnDelete(DeleteBehavior.NoAction);
    
        }
        public DbSet<Person> People { get; set; }
        public DbSet<Relationship> Relationships { get; set; }
    }
    

    现在 add-migration xxx 可以工作了:

        protected override void Up(MigrationBuilder migrationBuilder)
        {
    
            migrationBuilder.CreateTable(
                name: "People",
                columns: table => new
                {
                    ID = table.Column<int>(nullable: false)
                        .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
                    FirstName = table.Column<string>(nullable: true),
                    MiddleName = table.Column<string>(nullable: true),
                    LastName = table.Column<string>(nullable: true),
                    Email = table.Column<string>(nullable: true),
                    UserID = table.Column<string>(nullable: true)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_People", x => x.ID);
                    table.ForeignKey(
                        name: "FK_People_AspNetUsers_UserID",
                        column: x => x.UserID,
                        principalTable: "AspNetUsers",
                        principalColumn: "Id",
                        onDelete: ReferentialAction.Restrict);
                });
    
            migrationBuilder.CreateIndex(
                name: "IX_People_UserID",
                table: "People",
                column: "UserID");
    
            migrationBuilder.CreateTable(
                name: "Relationships",
                columns: table => new
                {
                    RelationshipID = table.Column<int>(nullable: false)
                        .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
                    Since = table.Column<DateTime>(nullable: false),
                    Kind = table.Column<int>(nullable: false),
                    MyID = table.Column<int>(nullable: false),
                    TheirID = table.Column<int>(nullable: false)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_Relationships", x => x.RelationshipID);
                    table.ForeignKey(
                        name: "FK_Relationships_People_MyID",
                        column: x => x.MyID,
                        principalTable: "People",
                        principalColumn: "ID");
                    table.ForeignKey(
                        name: "FK_Relationships_People_TheirID",
                        column: x => x.TheirID,
                        principalTable: "People",
                        principalColumn: "ID");
                });
    
            migrationBuilder.CreateIndex(
                name: "IX_Relationships_MyID",
                table: "Relationships",
                column: "MyID");
    
            migrationBuilder.CreateIndex(
                name: "IX_Relationships_TheirID",
                table: "Relationships",
                column: "TheirID");
        }
    
        protected override void Down(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.DropTable(
                name: "Relationships");
    
            migrationBuilder.DropTable(
                name: "People");
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-11-20
      • 2020-11-19
      • 2020-07-14
      • 1970-01-01
      • 1970-01-01
      • 2021-10-11
      • 1970-01-01
      • 2018-06-02
      相关资源
      最近更新 更多