Я пытался найти свой путь с EF последние пару дней / недель. В настоящее время я немного застрял в обработке внешних ключей, в этом случае у меня есть таблица с двумя FK для себя (пожалуйста, не задавайте вопросов о моем дизайне БД, так как это просто ситуация, с которой я сталкиваюсь, у меня нет возможности изменить структуру базы данных).

Я сократил свой код до следующего примера, в котором я использую одну таблицу, описанную классом Foo:

class Foo
{
    public int ID { get; set; }

    public string Data { get; set; }

    public int firstFkID { get; set; }

    public int secondFkID { get; set; }

    [ForeignKey("firstFkID")]
    public virtual Foo firstFk { get; set; }

    [ForeignKey("secondFkID")]
    public virtual Foo secondFk { get; set; }
}

Мой производный класс от DbContext:

class EFFKContext : DbContext
{
    public EFFKContext(string connectionString) : base(connectionString) { }

    public virtual DbSet<Foo> Foo { get; set; }
}

И, конечно же, код, в котором я все это использую:

static void Main(string[] args)
{
    SqlConnectionStringBuilder cnStrBuilder = new SqlConnectionStringBuilder()
    {
        DataSource = "(local)",
        InitialCatalog = "EF_FK",
        IntegratedSecurity = true
    };

    EFFKContext context = new EFFKContext(cnStrBuilder.ConnectionString);

    Foo foo = context.Foo.Find(3);

    Foo fFoo = foo.firstFk;

    Foo sFoo = foo.secondFk;
}

Когда я компилирую это, никаких проблем нет, но во время выполнения я получаю следующую ошибку:

Необработанное исключение типа System.InvalidOperationException произошло в> EntityFramework.dll

Дополнительная информация: Невозможно определить главный конец ассоциации> между типами RF_EF_FK.Foo и RF_EF_FK.Foo. Главный конец этой> ассоциации должен быть явно сконфигурирован с использованием либо> текучей связи> API, либо аннотаций данных.

Может ли кто-нибудь объяснить, почему я получаю эту ошибку, что она конкретно означает и указать направление, в котором мне придется изменить свой код, чтобы заставить его вести себя так, как я хочу?

Которая может получить объекты, на которые указывают два FK.

Я пробовал следующее:

  • Добавление дополнительных свойств навигации, возвращающих коллекцию, хотя это не дает желаемого решения. Кроме того, отношения не являются отношениями «один ко многим», так что это даже не кажется правильным.

  • Я также пробовал добавить код Fluent API, но опять же это не дало мне нужного решения.

Хотя я пробовал вышеуказанные вещи, вполне возможно, что я что-то там пропустил. Любая помощь приветствуется!


Изменить:

Продолжая поиски решения этой проблемы, я обнаружил, что добавление следующего в мой класс контекста решит проблему FK.

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{          
    modelBuilder.Entity<Foo>().HasOptional(f => f.secondFk).WithMany().HasForeignKey(f => f.secondFkID);
    modelBuilder.Entity<Foo>().HasOptional(f => f.firstFk).WithMany().HasForeignKey(f => f.firstFkID);
}

Теперь при загрузке объекта из базы данных мне нужно использовать функции Include, чтобы сразу включить связанные объекты, или использовать следующее, чтобы загрузить его позже:

context.Entry(sFoo).Reference("firstFk").Load();

Тем не менее, все еще не уверен, стоит ли это делать.

4
RFerwerda 16 Фев 2015 в 12:32

2 ответа

Лучший ответ

В связи с тем, что никаких других ответов, кроме ответа Джениш Рададия, не было, я опубликую свои собственные выводы в качестве ответа.

Продолжая поиски решения этой проблемы, я обнаружил, что добавление следующего в мой класс контекста решит проблему FK.

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{          
    modelBuilder.Entity<Foo>().HasOptional(f => f.secondFk).WithMany().HasForeignKey(f => f.secondFkID);
    modelBuilder.Entity<Foo>().HasOptional(f => f.firstFk).WithMany().HasForeignKey(f => f.firstFkID);
}

Теперь, при загрузке объекта из базы данных, мне нужно использовать функции Include, чтобы сразу включить связанные объекты, или использовать следующее, чтобы загрузить его позже:

context.Entry(sFoo).Reference("firstFk").Load();

Тем не менее, все еще не уверен, стоит ли это делать.

2
RFerwerda 19 Фев 2015 в 08:28

Возможно, вам потребуется сделать одно поле допускающим значение NULL. Я не очень в этом уверен.

Вместо этого вы можете использовать Fluent api для подготовки отношения модели.

class Foo
{
    public int ID { get; set; }

    public string Data { get; set; }

    public int firstFkID { get; set; }

    public int secondFkID { get; set; }

    //[ForeignKey("firstFkID")] <- remove this while using fluent api
    public virtual Foo firstFk { get; set; }

    //[ForeignKey("secondFkID")] <- remove this while using fluent api
    public virtual Foo secondFk { get; set; }
}

Попробуй это.

public class FooConfiguration : EntityTypeConfiguration<Foo>
{
    public FooConfiguration()
    {
        this.HasKey(x => x.ID);

        this.HasOptional(f => f.firstFk)
            .WithOptionalDependent(f => f.secondFk);
    }
}

Я также нашел один связанный поток stackoverflow => здесь

1
Community 23 Май 2017 в 12:06