我正在使用EF 4.1 Code First并尝试对以下内容进行建模。
public class Apple
{
public int Id {get;set;}
}
public class Banana
{
public int AppleId {get;set;}
public int Id {get;set;}
public virtual ICollection<Coconut> Coconuts {get;set;}
}
public class Coconuts
{
public int AppleId {get;set;}
public int Id {get;set;}
public virtual ICollection<Banana> Bananas {get;set;}
}
数据库看起来像这样。
这是一个不遵循EF约定的现有架构,因此我使用Fluent API将实体映射到数据库。映射看起来像这样。
public class BananaMapping : EntityTypeConfiguration<Banana>
{
public BananaMapping()
{
HasKey(e => new { e.AppleId, e.Id })
.ToTable("Bananas", "fruit");
Property(e => e.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
HasMany(e => e.Coconuts)
.WithMany(s => s.Bananas)
.Map(l =>
{
l.ToTable("BananaCoconuts", "fruit");
l.MapLeftKey("AppleId", "BananaId");
l.MapRightKey("AppleId", "CoconutId");
});
}
(苹果和椰子也被映射,但为简洁起见,此处省略)
如果我这样离开它,它将因共享列而生成MetadataException。
"Schema specified is not valid. Errors: (110,6) : error 0019: Each property name in a type must be unique. Property name 'AppleId' was already defined."
为了解决这个问题,我在BananaCoconuts
上创建了一个计算列,它只是公开了一个名为AppleId
的不同命名的副本,并将其称为BananaAppleId
。我独自离开了FK(显然)并将映射更改为这样......
HasMany(e => e.Coconuts)
.WithMany(s => s.Bananas)
.Map(l =>
{
l.ToTable("BananaCoconuts", "fruit");
l.MapLeftKey("BananaAppleId", "BananaId");
l.MapRightKey("AppleId", "CoconutId");
}
);
虽然有点臭和肯定是hacktastic,它确实让我超过MetadataException,直到我尝试从代码添加新链接。
var banana = dataContext.FindBanana(appleId, bananaId);
var coconut = dataContext.FindCoconut(appleId, coconutId);
banana.Coconuts.Add(coconut);
dataContext.SaveChanges();
保存更改会抛出DbUpdateException
An error occurred while saving entities that do not expose foreign key properties for their relationships. The EntityEntries property will return null because a single entity cannot be identified as the source of the exception. Handling of exceptions while saving can be made easier by exposing foreign key properties in your entity types. See the InnerException for details.
内在(实际上是异常情况下)......
{"The column \"BananaAppleId\" cannot be modified because it is either a computed column or is the result of a UNION operator."}
现在我没有想法了。 :)数据库模式准确地模拟了我们需要的东西(该计算列除外)。处理这个问题的最佳方法是什么?我并不是想让BananaAppleId
成为一个“真正的”列,更改外键,以及重复存储的数据,这些数据应该不会同步。
答案 0 :(得分:3)
连接表需要有4列作为主键,每一列都是主表的外键。列不能设置为计算,因为EF将通过发送所有4列值来插入记录。所以在你的情况下
HasMany(e => e.Coconuts)
.WithMany(s => s.Bananas)
.Map(l =>
{
l.ToTable("BananaCoconuts", "fruit");
l.MapLeftKey("BananaAppleId", "BananaId");
l.MapRightKey("CoconutAppleId", "CoconutId");
}
);
否则,您必须将连接表映射为单独的实体。