Разделение таблиц структуры Entity: не в иерархии одного и того же типа/не имеют действительного отношения одного к одному внешнему ключу

Я использую Entity Framework 6 с подходом Code-First, и я хочу, чтобы два объекта были помещены в одну и ту же таблицу. Что я делаю неправильно?

[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" и "Обзор" не могут совместно использовать таблицу "Обзор", потому что они не находятся в иерархии одного типа или не имеют действительной связи один к одному с внешним ключом с соответствующими первичными ключами между ними.

Что я делаю неправильно?

Ответ 1

Похоже, проблема заключалась в том, что связь интерпретировалась как один-на-0..1 вместо взаимно-однозначного.

Внешний ключ int PictureInfoId в конце отзыва был ненужным/проигнорированным, поэтому его непустота не привела к необходимости завершения проверки отношения. Удаление этого ненужного ключа и добавление атрибута [Обязательный] в навигационное свойство PictureInfo разрешили его.

Здесь скорректированный класс Review.

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

Ответ 2

Мне удалось достичь того, чего вы хотели с беглостью 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 и просмотра этот столбец должен иметь то же имя. Если вы хотите сохранить свойство первичного ключа PictureInfo с именем ReviewId, вы можете это сделать, но вам нужно будет сопоставить его имя с "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 и затем сопоставить их с одной и той же таблицей.

Ответ 3

Другой способ решить эту проблему - создать представление только с нужными полями. Затем сопоставьте объект с представлением.

Ответ 4

(Эти тесты и ошибки были написаны против 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; }
}

С указанными выше объектами я получил эту ошибку:

Невозможно определить главный конец связи между типы. Основной конец этой ассоциации должен быть явно сконфигурированный с использованием либо свободного API API, либо данных аннотации.

Вторая попытка

[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; }
}

Типы объектов "Обзор" и "PictureInfo" не могут совместно использовать таблицу "Обзор", потому что они не находятся в иерархии одного типа или не имеют действительное отношение одного к одному внешнему ключу с соответствующими первичными между ними.

Третья попытка

[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; }
}

Невозможно определить главный конец связи между типы. Основной конец этой ассоциации должен быть явно сконфигурированный с использованием либо свободного API 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; }
}

Ответ 5

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; }
    } 
}

Ответ 6

Ошибка вызвана тем, что определение таблицы дублируется в директиве таблицы "PictureInfo". Вам нужно только отредактировать эту директиву.

[Таблица ( "Обзор" )]Обзор общественного класса {... }

[Таблица ( "Обзор" )]открытый класс PictureInfo{... }

для

[Таблица ( "Обзор" )]Обзор общественного класса {... }

[Таблица ( "PictureInfo" )]открытый класс PictureInfo{... }