4

私は 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: 

この関係の原則的な終わりを特定するにはどうすればよいでしょうか?

モデル ビルダーの流暢な API を使用して次の構成を追加しようとしましたが、成功しませんでした。

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<Vehicle>()
        .HasRequired(v => v.Manufacturer)
        .WithRequiredDependent();
}
4

2 に答える 2

3

Manufacturer クラスには、Vehicles という外部キー プロパティが 1 つだけ必要です。

[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 はVehicleテーブルのサブクラス名 ( CarTruck )から取得した値を使用して、追加のDiscriminator列を生成します。

便宜上、Manufacturer に 2 つの追加の (非 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();
    }
}
于 2013-09-11T15:17:32.587 に答える
0

SQL Server 2012 と「移行」( 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; }

 }
于 2014-09-15T14:00:23.060 に答える