web-dev-qa-db-ja.com

エンティティフレームワークテーブルの分割:同じタイプ階層にない/有効な1対1の外部キー関係がない

Entity Framework 6を​​コードファーストアプローチで使用しています。2つのエンティティを同じテーブルに配置します。何が悪いのですか?

[Table("Review")]
public class Review
{
    public int Id { get; set; }
    public PictureInfo PictureInfo { get; set; }
    public int PictureInfoId { get; set; }
}

[Table("Review")]
public class PictureInfo
{
    [Key, ForeignKey("Review")]
    public int ReviewId { get; set; }
    public Review Review { get; set; }
}

発生するエラー:エンティティタイプ 'PictureInfo'と 'Review'は、同じタイプ階層にないか、一致する主キーとの有効な1対1の外部キー関係がないため、テーブル 'Review'を共有できません。

何が悪いのですか?

16
Andrew

問題は、関係が1対1ではなく1対0..1として解釈されることでした。

外部キーint PictureInfoIdレビュー終了時は不要/無視されていたため、null可能でないため、レビューの終了が必要な関係になりませんでした。この不要なキーを削除し、[必須]属性をPictureInfoナビゲーションプロパティに追加することで解決しました。

これが修正されたレビュークラスです。

[Table("Review")]
public class Review
{
    public int Id { get; set; }
    [Required]
    public PictureInfo PictureInfo { get; set; }
}
7
Andrew

Fluent APIであなたが望んだことをなんとか成し遂げました。 Fluent apiは、データアノテーションよりもはるかに豊富な構成オプションを提供します。エンティティクラスを少し変更しました。

public class Review
{
    public int Id { get; set; }
    public PictureInfo PictureInfo { get; set; }
}

外部キーの関係は両方のエンティティの主キーで行われるため、PictureInfoIdプロパティは必要ありません。

public class PictureInfo
{
    public int Id { get; set; }
    public Review Review { get; set; }
}

ReviewとPictureInfoは同じテーブルにマップされるため、同じ主キー列を共有する必要があるため、PictureInfoとReviewの場合、この列は同じ名前にする必要があります。 ReviewInfoという名前のPictureInfo主キープロパティを保持したい場合は、これを行うことができますが、その名前を "Id"にマップする必要があります。最後に、DbContext:

public class MyDbContext : DbContext
{
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Review>().HasKey( e => e.Id );
        modelBuilder.Entity<Review>()
            .HasRequired(e => e.PictureInfo)
            .WithRequiredDependent(e => e.Review);
        modelBuilder.Entity<Review>().Map(m => m.ToTable("Review"));
        modelBuilder.Entity<PictureInfo>().Map(m => m.ToTable("Review"));
        modelBuilder.Entity<PictureInfo>().HasKey(e => e.Id);

        base.OnModelCreating(modelBuilder);
    }

    public DbSet<Review> Reviews { get; set; }
    public DbSet<PictureInfo> PictureInfos { get; set; }
}

OnModelCreatingは、流れるようなAPIマッピング定義を保持します。両方のエンティティに同じ名前の主キーを定義し、それら2つのエンティティを1-1の関係でバインドしてから、それらを同じテーブルにマップするだけです。

7
mr100

(これらのテストとエラーはEF 6.1.3に対して作成されました)

最初の試み

[Table("Review")]
public class Review
{
    [Key]
    public int Id { get; set; }
    public PictureInfo PictureInfo { get; set; }
}

[Table("Review")]
public class PictureInfo
{
    [Key]
    public int Id { get; set; }
    public Review Review { get; set; }
}

上記のエンティティで、私はこのエラーを受け取りました:

タイプ間の関連付けの主要な終了を判別できません。この関連付けの主要な端は、リレーションシップFluent APIまたはデータアノテーションを使用して明示的に構成する必要があります。

2回目の試み

[Table("Review")]
public class Review
{
    [Key]
    public int Id { get; set; }

    [Required]
    public PictureInfo PictureInfo { get; set; }
}

[Table("Review")]
public class PictureInfo
{
    [Key]
    public int Id { get; set; }

    [Required]
    public Review Review { get; set; }
}

エンティティタイプ 'Review'と 'PictureInfo'は、同じタイプ階層にないか、一致する主キーとの有効な1対1の外部キー関係がないため、テーブル 'Review'を共有できません。

3回目の試み

[Table("Review")]
public class Review
{
    [Key]
    public int Id { get; set; }

    [Required, ForeignKey("Id")]
    public PictureInfo PictureInfo { get; set; }
}

[Table("Review")]
public class PictureInfo
{
    [Key]
    public int Id { get; set; }

    [Required, ForeignKey("Id")]
    public Review Review { get; set; }
}

タイプ間の関連付けの主要な終了を判別できません。この関連付けの主要な端は、リレーションシップFluent APIまたはデータアノテーションを使用して明示的に構成する必要があります。

作業コード

[Table("Review")]
public class Review
{
    [Key, ForeignKey("PictureInfo")]
    public int Id { get; set; }

    public PictureInfo PictureInfo { get; set; }
}

[Table("Review")]
public class PictureInfo
{
    [Key, ForeignKey("Review")]
    public int Id { get; set; }

    public Review Review { get; set; }
}
1
Mark Rucker

この問題を解決するもう1つの方法は、必要なフィールドのみを含むビューを作成することです。次に、エンティティをビューにマップします。

1
Greg Gum
using System.Linq;
using System.Data.Entity;
namespace Sample
{

    class Program
    {
        static void Main(string[] args)
        {
            using (var context = new EmployeeDBContext())
            {
                var result = context.Set<Employee>().Include(x => x.Department).ToArray();
            }
        }
    }

    public class EmployeeDBContext : DbContext
    {
        public EmployeeDBContext() : base("EmployeeDB") { }

        public DbSet<Employee> Employee { get; set; }
        public DbSet<Department> Department { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Department>().ToTable("Departments").HasKey(x => x.DepartmentId);
            modelBuilder.Entity<Employee>().ToTable("Employees").HasKey(x => x.Id);
            //ForeignKey mapping 
            modelBuilder.Entity<Employee>().HasRequired(x => x.Department).WithMany().HasForeignKey(x => x.DepartmentId);
            base.OnModelCreating(modelBuilder);
        }
    }

    //Domain Entity
    public class Employee
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public Department Department { get; set; }
        public int DepartmentId { get; set; }
    }

    //Domain Entity
    public class Department
    {
        public int DepartmentId { get; set; }
        public string DepartmentName { get; set; }
    } 
}
0
Code First