一段时间以来,我一直在域设计中遵循Object Calisthenics中的“一流收藏”规则。为了避免创建无用的“集合”表,我使用了Entity Framework中的table splitting配置。
但是如果出于某种原因,我有一个Parent
类,除了其ID和子级集合之外,没有其他属性,则会出现异常:
InvalidOperationException:ReferentialConstraint中的从属属性被映射到商店生成的列。列:“ Id”。
奇怪的是,数据库创建正确,可以从中查询,但是无法保存。
如果我只是简单地向Parent
添加另一个属性,问题就会消失,这更加奇怪。
我将其范围缩小到一个非常简单的测试用例:
Program.cs
class Program
{
static void Main(string[] args)
{
using (var context = new MyContext(new DropCreateDatabaseAlways<MyContext>()))
{
context.Set<Parent>().Find(1);
}
using (var context = new MyContext(new CreateDatabaseIfNotExists<MyContext>()))
{
context.Set<Parent>().Add(
new Parent()
{
ChildrenCollection = new ChildrenCollection()
{
List = new List<Child>() { new Child() }
}
});
context.SaveChanges(); // Exception thrown here
}
}
}
域
public class Parent
{
public int Id { get; set; }
public virtual ChildrenCollection ChildrenCollection { get; set; }
}
public class ChildrenCollection
{
public int Id { get; set; }
public virtual IList<Child> List { get; set; }
}
public class Child
{
public int Id { get; set; }
}
Context
public class MyContext : DbContext
{
public MyContext(IDatabaseInitializer<MyContext> dbInitializer)
: base(nameOrConnectionString: GetConnectionString())
{
Database.SetInitializer(dbInitializer);
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new ChildrenCollectionConfiguration());
modelBuilder.Configurations.Add(new ParentConfiguration());
base.OnModelCreating(modelBuilder);
}
private static string GetConnectionString()
{
return @"Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=TestEntityFramework;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=True;ApplicationIntent=ReadWrite;MultiSubnetFailover=False;MultipleActiveResultSets=true;";
}
}
配置
public class ParentConfiguration : EntityTypeConfiguration<Parent>
{
public ParentConfiguration()
{
HasRequired(x => x.ChildrenCollection)
.WithRequiredPrincipal();
}
}
public class ChildrenCollectionConfiguration : EntityTypeConfiguration<ChildrenCollection>
{
public ChildrenCollectionConfiguration()
{
#region Configure Table Splitting
var parentTable = typeof(Parent).Name;
ToTable(parentTable);
HasMany(x => x.List)
.WithRequired()
.Map(x =>
{
x.MapKey(string.Concat(parentTable, "_Id"));
});
#endregion
}
}
直接从DbContext类进行配置时,从父级到子级保持配置的逻辑顺序是很自然的,但是当您单击separate the config using EntityTypeConfiguration<TEntity>
时,情况可能并非如此。
这似乎是此特定情况下Entity Framework中的错误,因为它在大多数情况下都有效。
为了确保它始终有效,只需先为层次结构中较高级别的类调用配置。
EntityTypeConfiguration<TEntity>