entity-framework - EF Core 3. 定义与现有数据库的多对多关系
问题描述
我有一个非常旧的现有 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。
- 然后如何与这些实体建立“多对多”关系?“链接表”实际上是在数据库中定义“多对一对多”关系,在我看来,我不想在我的实体中公开一些东西。
这么多要学...
解决方案
在我看来,您最好在 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);
推荐阅读
- php - 为什么可以从php中的数组调用变量函数?
- javascript - 使用 css 延迟不透明度过渡
- sqlalchemy - 使自动增量 ID 以预定义的数字开头
- linux - 为什么 Buildroot 不考虑新的 device_table.txt?
- expo - Expo:expo-av 在后台播放新的音频文件?
- google-sheets - GS 查询将一列(Last,First)拆分为 2 列
- python - PySpark:如何对数组中实际上是字符串列的字典值求和
- elasticsearch - 如何根据字段值将一个索引复制到多个索引中?
- audit-logging - 审核的排除过滤器增加了显着的延迟
- google-cloud-platform - 谷歌云计算虚拟机实例未列出