EF Core 3.定义与现有数据库的多对多关系

时间:2019-09-27 11:20:49

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

我有一个非常老的现有SQL DB,架构也不是很好,但是我不能更改它,必须忍受它。

我是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。并且数据类型与[People]表中的[PeopleID为varchar(10),但此链接表中的为nvarchar(255)]不匹配。还要使用varchar vs 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。
  • 然后如何与这些实体建立“多对多”关系? “链接表”实际上是在数据库中定义“多对多”关系,在我看来并没有我想要在实体中公开的东西。

有很多东西要学习...

1 个答案:

答案 0 :(得分:-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);