EF6 使用相同的列名映射多对多
EF6 mapping many-to-many using same column name
在现有的 sqlite 数据库中,我有 3 tables。
首先是带有“events”的table,它使用了“id”和“licence_key”的复合主键。
第二个 table 包含 `codes`,这也使用了 `session_code` 和 `licence_key` 的复合键。
最后的 table 是来自以下 sql 的关联 table:
CREATE TABLE `event_code` (
`event_id` INTEGER NOT NULL,
`session_code` TEXT NOT NULL,
`licence_key` TEXT NOT NULL,
CONSTRAINT `event_code$event_id_session_code_licence_key_PK` PRIMARY KEY(`event_id` ASC,`session_code` ASC,`licence_key` ASC),
CONSTRAINT `event_code$event_id_licence_key_FK` FOREIGN KEY(`event_id`, `licence_key`) REFERENCES `event`(`id`, `licence_key`) ON UPDATE CASCADE ON DELETE CASCADE,
CONSTRAINT `event_code$session_code_licence_key_FK` FOREIGN KEY(`session_code`, `licence_key`) REFERENCES `code`(`session_code`, `licence_key`) ON UPDATE CASCADE ON DELETE CASCADE
);
我的程序使用 entity framework 和流畅的映射来加载和存储这些 table 中的对象。
在 EF6 中,我认为映射的相关部分应该如下所示:
modelBuilder.Entity<EF6EventInformation>().HasMany(eventInfo => eventInfo.InternalSessionCodes).WithMany().Map(mapping =>
{
mapping.ToTable("event_code");
mapping.MapLeftKey("event_id", "licence_key");
mapping.MapRightKey("session_code", "licence_key");
});
但是,这会引发异常:
System.Data.Entity.ModelConfiguration.ModelValidationException: One or more validation errors were detected during model generation:
licence_key: Name: Each property name in a type must be unique. Property name 'licence_key' is already defined.
看来我不能重复使用同一个列。
当然,我可以更改数据库设计并将两个实体的 licence_key 存储在它们自己单独的列中,但是因为每个 licence_key 的值总是必须与另一个看起来不匹配的值相匹配特别有用。
有没有什么方法可以在不更改数据库设计的情况下正确设置此映射?
这似乎是通过隐式连接 table 对 many-to-many 的 EF6 映射的限制。
可以在不改变数据库结构的情况下映射关系,但通过添加显式连接实体和映射 many-to-many 为两个改变实体模型 many-to-one。
所以您需要这样的实体:
public class EventCode
{
public int event_id { get; set; }
public int session_code { get; set; }
public int license_key { get; set; }
public Event Event { get; set; }
public Code Code { get; set; }
}
然后将现有的 collection 导航 属性 更改为如下内容:
public ICollection<EventCode> EventCodes { get; set; }
并像这样使用流畅的配置:
modelBuilder.Entity<EventCode>()
.ToTable("event_code");
modelBuilder.Entity<EventCode>()
.HasKey(e => new { e.event_id, e.session_code, e.license_key });
modelBuilder.Entity<EventCode>()
.HasRequired(e => e.Event)
.WithMany(e => e.EventCodes)
.HasForeignKey(e => new { e.event_id, e.license_key });
modelBuilder.Entity<EventCode>()
.HasRequired(e => e.Code)
.WithMany()
.HasForeignKey(e => new { e.session_code, e.license_key });
当然你可以创建更好的 C# 常规 属性 名称
public class EventCode
{
public int EventId { get; set; }
public int SessionCode { get; set; }
public int LicenseKey { get; set; }
public Event Event { get; set; }
public Code Code { get; set; }
}
并将它们映射到现有的 table 列名称
但这并没有从根本上改变关系映射解决方案。
modelBuilder.Entity<EventCode>()
.ToTable("Event_Code");
modelBuilder.Entity<EventCode>()
.HasKey(e => new { e.EventId, e.SessionCode, e.LicenseKey });
modelBuilder.Entity<EventCode>().Property(e => e.EventId)
.HasColumnName("event_id");
modelBuilder.Entity<EventCode>().Property(e => e.SessionCode)
.HasColumnName("session_code");
modelBuilder.Entity<EventCode>().Property(e => e.LicenseKey)
.HasColumnName("license_key");
modelBuilder.Entity<EventCode>()
.HasRequired(e => e.Event)
.WithMany(e => e.EventCodes)
.HasForeignKey(e => new { e.EventId, e.LicenseKey });
modelBuilder.Entity<EventCode>()
.HasRequired(e => e.Code)
.WithMany()
.HasForeignKey(e => new { e.SessionCode, e.LicenseKey });
两种many-to-many映射方式各有利弊,但这里根本就没有选择。
在现有的 sqlite 数据库中,我有 3 tables。
首先是带有“events”的table,它使用了“id”和“licence_key”的复合主键。
第二个 table 包含 `codes`,这也使用了 `session_code` 和 `licence_key` 的复合键。
最后的 table 是来自以下 sql 的关联 table:
CREATE TABLE `event_code` (
`event_id` INTEGER NOT NULL,
`session_code` TEXT NOT NULL,
`licence_key` TEXT NOT NULL,
CONSTRAINT `event_code$event_id_session_code_licence_key_PK` PRIMARY KEY(`event_id` ASC,`session_code` ASC,`licence_key` ASC),
CONSTRAINT `event_code$event_id_licence_key_FK` FOREIGN KEY(`event_id`, `licence_key`) REFERENCES `event`(`id`, `licence_key`) ON UPDATE CASCADE ON DELETE CASCADE,
CONSTRAINT `event_code$session_code_licence_key_FK` FOREIGN KEY(`session_code`, `licence_key`) REFERENCES `code`(`session_code`, `licence_key`) ON UPDATE CASCADE ON DELETE CASCADE
);
我的程序使用 entity framework 和流畅的映射来加载和存储这些 table 中的对象。
在 EF6 中,我认为映射的相关部分应该如下所示:
modelBuilder.Entity<EF6EventInformation>().HasMany(eventInfo => eventInfo.InternalSessionCodes).WithMany().Map(mapping =>
{
mapping.ToTable("event_code");
mapping.MapLeftKey("event_id", "licence_key");
mapping.MapRightKey("session_code", "licence_key");
});
但是,这会引发异常:
System.Data.Entity.ModelConfiguration.ModelValidationException: One or more validation errors were detected during model generation:
licence_key: Name: Each property name in a type must be unique. Property name 'licence_key' is already defined.
看来我不能重复使用同一个列。
当然,我可以更改数据库设计并将两个实体的 licence_key 存储在它们自己单独的列中,但是因为每个 licence_key 的值总是必须与另一个看起来不匹配的值相匹配特别有用。
有没有什么方法可以在不更改数据库设计的情况下正确设置此映射?
这似乎是通过隐式连接 table 对 many-to-many 的 EF6 映射的限制。
可以在不改变数据库结构的情况下映射关系,但通过添加显式连接实体和映射 many-to-many 为两个改变实体模型 many-to-one。
所以您需要这样的实体:
public class EventCode
{
public int event_id { get; set; }
public int session_code { get; set; }
public int license_key { get; set; }
public Event Event { get; set; }
public Code Code { get; set; }
}
然后将现有的 collection 导航 属性 更改为如下内容:
public ICollection<EventCode> EventCodes { get; set; }
并像这样使用流畅的配置:
modelBuilder.Entity<EventCode>()
.ToTable("event_code");
modelBuilder.Entity<EventCode>()
.HasKey(e => new { e.event_id, e.session_code, e.license_key });
modelBuilder.Entity<EventCode>()
.HasRequired(e => e.Event)
.WithMany(e => e.EventCodes)
.HasForeignKey(e => new { e.event_id, e.license_key });
modelBuilder.Entity<EventCode>()
.HasRequired(e => e.Code)
.WithMany()
.HasForeignKey(e => new { e.session_code, e.license_key });
当然你可以创建更好的 C# 常规 属性 名称
public class EventCode
{
public int EventId { get; set; }
public int SessionCode { get; set; }
public int LicenseKey { get; set; }
public Event Event { get; set; }
public Code Code { get; set; }
}
并将它们映射到现有的 table 列名称
但这并没有从根本上改变关系映射解决方案。
modelBuilder.Entity<EventCode>()
.ToTable("Event_Code");
modelBuilder.Entity<EventCode>()
.HasKey(e => new { e.EventId, e.SessionCode, e.LicenseKey });
modelBuilder.Entity<EventCode>().Property(e => e.EventId)
.HasColumnName("event_id");
modelBuilder.Entity<EventCode>().Property(e => e.SessionCode)
.HasColumnName("session_code");
modelBuilder.Entity<EventCode>().Property(e => e.LicenseKey)
.HasColumnName("license_key");
modelBuilder.Entity<EventCode>()
.HasRequired(e => e.Event)
.WithMany(e => e.EventCodes)
.HasForeignKey(e => new { e.EventId, e.LicenseKey });
modelBuilder.Entity<EventCode>()
.HasRequired(e => e.Code)
.WithMany()
.HasForeignKey(e => new { e.SessionCode, e.LicenseKey });
两种many-to-many映射方式各有利弊,但这里根本就没有选择。