【问题标题】:EF Core 3. Defining a many-to-many relation with existing DBEF Core 3. 定义与现有数据库的多对多关系
【发布时间】:2019-09-30 01:49:49
【问题描述】:

我有一个非常旧的现有 SQL 数据库,架构不是很好,但我无法更改它,我必须忍受它。

我是 Entity Framework 的新手,正在使用 EF Core 3 来尝试构建一个基本的 CRUD 应用程序。我在处理“多对多”关系时遇到了困难。

在下面的示例中,我将提供场景的缩减/虚构再现。

所以,在数据库中,我有两个表 [People] 和 [The_Cars],还有一个“链接”表是 [People__The_Cars]。是的,可怕的表名......

每个表的定义如下:

CREATE TABLE [dbo].[People](
    [PeopleID] [varchar](10) NOT NULL),
    [Name] [varchar](255) NOT NULL)

这有一个 PeopleID 的主键

CREATE TABLE [dbo].[The_Cars](
    [car_id] [int] NOT NULL,
    [car_name] [varchar](255) NOT NULL)

这没有主键....

CREATE TABLE [dbo].[People__The_Cars](
    [People__The_Cars_ID] [int] NOT NULL,
    [car_name] [nvarchar](255) NOT NULL,
    [PeopleID] [nvarchar](255) NOT NULL,

这确实有一个主键,但没有外键。汽车“FK”是名字,而不是ID。并且数据类型不匹配 [PeopleID 是 [People] 表中的 varchar(10),但在此链接表中是 nvarchar(255)]。也可以使用 varchar 与 nvarchar。

在 C# 中,我创建了一些类来用经过整理的名称来表示它们:

为了[人]

public class People
    {
        [StringLength(10)]
        [Required]
        public string ID{ get; set; }

        [StringLength(255)]
        [Required]
        public string Name { get; set; }

    public ICollection<People__The_Cars> PeopleCars{ get; set; }
}

为 [The_Cars]

public class The_Cars
    {
        [Required]
        public int Id{ get; set; }

        [StringLength(255)]
        [Required]
        public string Name { get; set; }

    public ICollection<People__The_Cars> PeopleCars{ get; set; }
}

对于链接表

public class People__The_Cars
    {
        [Required]
        public int Id{ get; set; }

        [StringLength(10)]
        [Required]
        public string PeopleId { get; set; }

        [StringLength(255)]
        [Required]
        public string CarName { get; set; }

public People Person{ get; set; }
public The_Cars Car{ get; set; }
}

(数据注释反映主表的数据类型)

现在进入数据上下文类

public class MyContext : DbContext
{
    public OpdxDestinationsContext(DbContextOptions<MyContext> options)
        : base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder
            .Entity<People>(e =>
            {
                e.HasKey(i => i.Id);
                e.Property(i => i.Id).HasColumnName("PeopleID");
            });

        modelBuilder
            .Entity<People__The_Cars>(e =>
            {
                e.HasKey(i => i.Name);
                e.Property(i => i.Id).HasColumnName("People__The_Cars_ID");
                e.Property(i => i.CarName).HasColumnName("car_name");
            });

        modelBuilder
            .Entity<Software_Vendor_Destinations>(e =>
            {
                e.HasKey(i => new {i.PeopleId, i.CarName });
                e.Property(i => i.Id).HasColumnName("Software_Vendor_Destinations_Id");
                e.Property(i => i.CarName).HasColumnName("car_name");
                e.Property(i => i.DestinationId).HasColumnName("PeopleID");
            });

        modelBuilder.Entity<People__The_Cars>()
            .HasOne(x => x.People)
            .WithMany(m => m.PeopleCars)
            .HasForeignKey(x => x.CarName);

        modelBuilder.Entity<People__The_Cars>()
            .HasOne(x => x.Car)
            .WithMany(m => m.PeopleCars)
            .HasForeignKey(x => x.PeopleId);

        base.OnModelCreating(modelBuilder);
    }

    public DbSet<People> People{ get; set; }

    public DbSet<Cars> Cars{ get; set; }
}

所以,几个问题。

  • 我对没有键的表使用了“HasKey”。他们应该这样做。这是不好的做法,还是我应该诚实并在丢失时使用 HasNoKey。
  • 然后如何设置与这些实体的“多对多”关系? “链接表”实际上是在数据库中定义“多对一对多”关系,在我看来,我不想在我的实体中公开一些东西。

要学的太多了……

【问题讨论】:

    标签: entity-framework .net-core entity-framework-core


    【解决方案1】:

    在我看来,最好在 Db 中使用与在表示 db 表的类中使用相同的列名。 所以我不会这样做:

    e.Property(i => i.ID).HasColumnName("People__The_Cars_ID");
    e.Property(i => i.CarName).HasColumnName("car_name");
    

    您也可以忽略 People__The_Cars 的 ID,方法是忽略它并删除 [Required] 属性:

    e.Ignore(i => i.ID);
    

    那么我建议你像下面这样定义连接表的关系

    如果 CarName 是唯一的:

    e.HasOne(o => o.Car).WithMany(m => m.PeopleCars).HasForeignKey(f => f.CarName);
    e.HasOne(o => o.Person).WithMany(m => m.PeopleCars).HasForeignKey(f => f.PeopleID);
    

    否则,有一个名为 CarID 的 int 属性:

    public class People__The_Cars
    {
        public int ID { get; set; }
    
        [StringLength(10)]
        [Required] public string PeopleID { get; set; }
    
        [StringLength(255)]
        [Required]
        public string CarName { get; set; }
    
        [Required]
        public int CarID { get; set; }
    
        public People Person { get; set; }
        public The_Cars Car { get; set; }
    }
    

    然后像下面这样定义它们之间的关系:

     e.HasOne(o => o.Car).WithMany(m => m.PeopleCars).HasForeignKey(f => f.CarName);
     e.HasOne(o => o.Person).WithMany(m => m.PeopleCars).HasForeignKey(f => f.CarID);
    

    【讨论】:

    • 如果数据库有可怕的名称,您最不想做的就是将它们导入您的应用程序。此外,您可以对非键属性使用 FK,但该属性必须配置为备用键。
    猜你喜欢
    • 1970-01-01
    • 2022-10-25
    • 2021-10-11
    • 1970-01-01
    • 2020-03-23
    • 2018-06-02
    • 1970-01-01
    • 2019-01-19
    • 1970-01-01
    相关资源
    最近更新 更多