我正在使用Entity Framework 5 Code First,我对汽车制造商,汽车和卡车有以下型号:
public class Manufacturer
{
public int Id { get; set; }
public string Name { get; set; }
[ForeignKey("ManufacturerId")]
public virtual List<Car> Cars { get; set; }
[ForeignKey("ManufacturerId")]
public virtual List<Truck> Trucks { get; set; }
}
public class Vehicle
{
public int Id { get; set; }
public string Colour { get; set; }
public int ManufacturerId { get; set; }
public virtual Manufacturer Manufacturer { get; set; }
}
public class Car : Vehicle
{ }
public class Truck : Vehicle
{ }
public class Context : DbContext
{
public DbSet<Manufacturer> Manufacturers { get; set; }
public DbSet<Vehicle> Vehicles { get; set; }
}
对于开发和测试,我按如下方式播种数据:
public class DbInitialiser : DropCreateDatabaseAlways<Context>
{
protected override void Seed(Context context)
{
var manufacturers = new List<Manufacturer>
{
new Manufacturer
{
Name = "Test Manufacturer",
Cars = new List<Car>
{
new Car { Colour = "Blue" },
new Car { Colour = "Green" }
},
Trucks = new List<Truck>
{
new Truck { Colour = "Red" }
}
},
new Manufacturer
{
Name = "Another Manufacturer",
Cars = new List<Car>
{
new Car { Colour = "Pink" }
}
}
};
manufacturers.ForEach(x => context.Manufacturers.Add(x));
}
}
但是当我使用上下文时,我得到以下异常: 无法确定'EF_Associations.Vehicle_Manufacturer'关系的主要结束。多个添加的实体可能具有相同的主键。
堆栈追踪:
System.Data.DataException was unhandled
HResult=-2146233087
Message=An exception occurred while initializing the database. See the InnerException for details.
Source=EntityFramework
StackTrace:
at System.Data.Entity.Internal.InternalContext.PerformInitializationAction(Action action)
at System.Data.Entity.Internal.InternalContext.PerformDatabaseInitialization()
at System.Data.Entity.Internal.LazyInternalContext.<InitializeDatabase>b__4(InternalContext c)
at System.Data.Entity.Internal.RetryAction`1.PerformAction(TInput input)
at System.Data.Entity.Internal.LazyInternalContext.InitializeDatabaseAction(Action`1 action)
at System.Data.Entity.Internal.LazyInternalContext.InitializeDatabase()
at System.Data.Entity.Internal.InternalContext.Initialize()
at System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type entityType)
at System.Data.Entity.Internal.Linq.InternalSet`1.Initialize()
at System.Data.Entity.Internal.Linq.InternalSet`1.GetEnumerator()
at System.Data.Entity.Infrastructure.DbQuery`1.System.Collections.Generic.IEnumerable<TResult>.GetEnumerator()
at EF_Associations.Program.Main(String[] args) in c:\temp\EF-Associations\Program.cs:line 19
...
InnerException: System.Data.Entity.Infrastructure.DbUpdateException
HResult=-2146233087
Message=Unable to determine the principal end of the 'EF_Associations.Vehicle_Manufacturer' relationship. Multiple added entities may have the same primary key.
Source=EntityFramework
StackTrace:
at System.Data.Entity.Internal.InternalContext.SaveChanges()
at System.Data.Entity.Internal.LazyInternalContext.SaveChanges()
at System.Data.Entity.DbContext.SaveChanges()
at System.Data.Entity.DropCreateDatabaseAlways`1.InitializeDatabase(TContext context)
at System.Data.Entity.Database.<>c__DisplayClass2`1.<SetInitializerInternal>b__0(DbContext c)
at System.Data.Entity.Internal.InternalContext.<>c__DisplayClass8.<PerformDatabaseInitialization>b__6()
at System.Data.Entity.Internal.InternalContext.PerformInitializationAction(Action action)
InnerException: System.Data.UpdateException
HResult=-2146233087
Message=Unable to determine the principal end of the 'EF_Associations.Vehicle_Manufacturer' relationship. Multiple added entities may have the same primary key.
Source=System.Data.Entity
StackTrace:
at System.Data.Mapping.Update.Internal.UpdateTranslator.RegisterEntityReferentialConstraints(IEntityStateEntry stateEntry, Boolean currentValues)
at System.Data.Mapping.Update.Internal.UpdateTranslator.RegisterReferentialConstraints(IEntityStateEntry stateEntry)
at System.Data.Mapping.Update.Internal.UpdateTranslator.PullModifiedEntriesFromStateManager()
at System.Data.Mapping.Update.Internal.UpdateTranslator.ProduceCommands()
at System.Data.Mapping.Update.Internal.UpdateTranslator.Update(IEntityStateManager stateManager, IEntityAdapter adapter)
at System.Data.EntityClient.EntityAdapter.Update(IEntityStateManager entityCache)
at System.Data.Objects.ObjectContext.SaveChanges(SaveOptions options)
at System.Data.Entity.Internal.InternalContext.SaveChanges()
InnerException:
我如何指定这种关系的原则结束?
我尝试通过模型构建器fluent API添加以下配置,但没有成功:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Vehicle>()
.HasRequired(v => v.Manufacturer)
.WithRequiredDependent();
}
答案 0 :(得分:3)
您的制造商级别必须只有一个外键属性:Vehicles。
[ForeignKey("ManufacturerId")]
public virtual List<Vehicle> Vehicles { get; set; }
您必须修改种子方法才能使用此单个FK属性。 EF将创建一个从实体类的继承链推断出的每层次表模型:
protected override void Seed(Context context)
{
var manufacturers = new List<Manufacturer>
{
new Manufacturer
{
Name = "Test Manufacturer",
Vehicles = new List<Vehicle>
{
new Car {Colour = "Blue" },
new Car {Colour = "Green" },
new Truck {Colour = "Red" }
}
},
new Manufacturer
{
Name = "Another Manufacturer",
Vehicles = new List<Vehicle>
{
new Car {Colour = "Pink" }
}
}
};
manufacturers.ForEach(x => context.Manufacturers.Add(x));
context.SaveChanges();
}
按照惯例,EF会生成一个额外的 Discriminator 列,其值来自 Car , Truck ) >车辆表。
为方便起见,您可以在Manufacturer上创建另外两个(非FK)属性,每个属性包含一个特定于继承的OfType查询:
public IEnumerable<Car> Cars
{
get
{
return this.Vehicles.OfType<Car>();
}
}
public IEnumerable<Truck> Trucks
{
get
{
return this.Vehicles.OfType<Truck>();
}
}
并使用它们来查询:
using (var db = new Context())
{
foreach (var manufacturer in db.Manufacturers)
{
var cars = manufacturer.Cars.ToList();
var trucks = manufacturer.Trucks.ToList();
}
}
答案 1 :(得分:0)
我使用SQL Server 2012和&#39;迁移&#39;进行了测试。 (http://msdn.microsoft.com/en-us/data/jj591621.aspx)
按如下方式对类进行建模:
[Table("Manufacturer")]
public class Manufacturer
{
public Funcionario()
{
Cars = new List<Car>();
Trucks = new List<Truck>();
}
[Key]
[Required]
[Column("Id", TypeName = "INT")]
public int Id { get; set; }
[Column("Name", TypeName = "VARCHAR")]
public string Name { get; set; }
public virtual ICollection<Car> Cars { get; set; }
public virtual ICollection<Truck> Trucks { get; set; }
}
[Table("Vehicle")]
public class Vehicle
{
[Key]
[Required]
[Column("Id", TypeName = "INT")]
public int Id { get; set; }
[Column("Colour", TypeName = "VARCHAR")]
public string Colour { get; set; }
[Column("ManufacturerId", TypeName = "INT")]
public int ManufacturerId { get; set; }
[ForeignKey("ManufacturerId")]
public virtual Manufacturer Manufacturer { get; set; }
}
[Table("Car")]
public class Car : Vehicle
{ }
[Table("Truck")]
public class Truck : Vehicle
{ }
public class Context : DbContext
{
public DbSet<Manufacturer> Manufacturers { get; set; }
public DbSet<Vehicle> Vehicles { get; set; }
public DbSet<Car> Cars { get; set; }
public DbSet<Truck> Trucks { get; set; }
}