Entity Framework с внешними ключами

Вкратце, как Entity Framework должна работать со связанными таблицами.

aspnetcore 2.0

public class Table1{
    [Key]
    public int Id{get;set;}

    [ForeignKey("Table2")]
    public int Table2Id {get;set;}
    public virtual Table2 Table2{get;set;}
}

public class Table2{
    [Key]
    public int Id{get;set;}

}

Я предположил, что с заявлением

var t1 = context.Table1List.FirstOrDefault( j => j.Id == 1)

автоматически заполнил бы Table2, но t1.Table2 имеет значение null.

Если бы я должен был вызвать context.Table2List.FirstOrDe ..... тогда t1.Table2 заполняется даже без установки свойства. Таким образом, EF распознает, что связь просто не заполняется, пока я физически не позвоню в БД.

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

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

Таблицы 1 и 2 связаны друг с другом только один к одному.

Ваш дизайн сбивает с толку - должен ли Id быть первичным ключом Table1 или внешним ключом Table2? Не могли бы вы определить SQL-определение обеих таблиц?

Rui Jarimba 02.10.2018 17:35

Вам нужно добавить включение в заполненную таблицу 2: context.Table1List.Include(t => t.Table2).FirstOrDefault( j => j.Id == 1)

agua from mars 02.10.2018 17:40

Пожалуйста, проверьте мой ответ.

AmirReza-Farahlagha 02.10.2018 17:41

@aguafrommars Совершенно верно. такой же, как мой ответ.

AmirReza-Farahlagha 02.10.2018 17:44
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
4
101
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Оставляя разводку в основном на усмотрение и предполагая отношение «1 ко многим», вы хотели создать набор моделей, которые выглядят так?

public class Table1
{
    public int Id { get; set; }     // Primary key by convention
    [ForeignKey("Table2")]
    public int Table2Id { get; set; }
    public Table2 Table2 { get; set; }
}

public class Table2
{
    public int Id { get; set; }     //Primary key by convention
    public ICollection<Table1> Table1s { get; set; }
}

см. комментарий к AmirReza-Farahlagha

Mike 02.10.2018 18:05
Ответ принят как подходящий

Обновлять:

Вы должны изменить свою модель, например:

public class Table1{
    public int Id{get; set;} //Primary key by convention
    [ForeignKey("Table2")]
    public int Table2Id{get; set;}
    public virtual Table2 Table2{get; set;}
}

public class Table2{
    public int Id{get; set;} //Primary key by convention
    public virtual Table1 Table1{get; set;}
}

И в вашем контексте вы должны установить это:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    // Configure table1 & table2 entity
    modelBuilder.Entity<Table2>()
                .HasOptional(s => s.Table1) // Mark Table1 property optional in Table2 entity
                .WithRequired(ad => ad.Table2); // mark Table1 property as required in Table2 entity. Cannot save Table1 without Table
}

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

var result  = var t1 = context.Table1List.Include(x=>x.Table2).FirstOrDefault( j => j.Id == 1);

с этим кодом у вас есть данные о связанной таблице.

Если хотите, я могу создать для вас больше образцов.

Вы только что скопировали / вставили определения классов из ответа @spender? Большой LOL

Rui Jarimba 02.10.2018 17:47

Не повезло. У меня уже есть много моделей, настроенных таким образом. они тоже не работают. Однако я считаю, что вы соглашаетесь с предположением, что EF должен заполнять их автоматически. Также таблицы 1 и 2 имеют отношение 1 к 1. Таким образом, список table1s не является верным утверждением. Я считаю, что моя модель показывает это. Также в таблицах 1 и 2 используются идентификаторы. Если бы я запустил ваш код, он не нашел бы Table2Id.

Mike 02.10.2018 18:04

@Mike Вы выбрали виртуальную собственность?

AmirReza-Farahlagha 02.10.2018 18:29

Я удалил последний комментарий ... добавление Include сработало. Это все, что я сделал. Однако у меня сложилось впечатление, что мне не придется этого делать. и добавление include по сути то же самое, что я пишу еще один оператор для выборки таблицы. Не думаю, что пробовал использовать параметр WithRequired в OnModelCreating. это выглядит положительно. Я тоже попробую. Однако ваш пример все еще неверен. Столбца с именем Table2Id нет. Просто Table1 и 2 имеют один и тот же идентификатор. Если бы мне пришлось добавить атрибут Column ("..."), то я получил бы повторяющуюся ошибку. Мой пример не показывает виртуальный, но мой код показывает.

Mike 02.10.2018 18:39

@Mike На мой взгляд, ваша проблема в вашей таблице, потому что она неверна, пожалуйста, проверьте эту строку entityframeworktutorial.net/code-first/…, чтобы узнать информацию о создании таблицы.

AmirReza-Farahlagha 02.10.2018 19:03

Я не думаю, что ошибка связана с моим кодом или, по крайней мере, с моими моделями и БД, потому что добавление Include (func) работало без ошибок. Итак, это говорит мне, что это параметр, который установлен неправильно. Я отметил наш ответ, потому что он сработал. Просто не так, как я хотел.

Mike 02.10.2018 20:48

@ Майк, я правда не понимаю, ты тестируешь метод Include ?? Если да, то какой у вас результат? У вас есть ошибки ?? Я думаю, вы получаете firstordefault, и прежде всего данные, нет данных о table2

AmirReza-Farahlagha 02.10.2018 20:59

как упоминалось в двух комментариях выше. Да, я протестировал включение, и это сработало. Вот почему я поставил вам оценку.

Mike 02.10.2018 21:38

То, что вам нужно, называется Ленивая загрузка

Проверив документацию, вы увидите, что вы должны явно включить отложенную загрузку:

.AddDbContext<BloggingContext>(
    b => b.UseLazyLoadingProxies()
          .UseSqlServer(myConnectionString));

И ваше свойство Table2 должно быть virtual:

public class Table1 
{  
    public virtual Table2 Table2{get;set;}
}

Вам даже не нужен внешний ключ Id!

Я попробую отложить загрузку ... Думаю, я пробовал это раньше, но не помню, почему id не работал. Пример, который у меня был, немного отличался от вашего. Вернемся к вам по этому поводу. Атрибут внешнего ключа понадобится вам, если у вас нет точного формата для свойств или если вы не установили его в onModelBuilding. Ваше последнее утверждение не совсем верно.

Mike 02.10.2018 18:09

@ Майк, конечно, проверьте также эта документация. И, как я вижу, вы используете оба Key. ForeignKey, вам следует ввести новое свойство для вашего внешнего ключа.

Yurii N. 02.10.2018 18:23

Нет опции для UseLazyLoadingProxies, есть ли для этого конкретная ссылка?

Mike 02.10.2018 18:25

Обратите внимание: Эта функция была представлена ​​в EF Core 2.1. Какая у вас версия EF Core?

Yurii N. 02.10.2018 19:42

2.0 AmirReza ... помогло просто добавление Include в контекст. На тот момент все работало.

Mike 02.10.2018 20:45

@Mike Да, это еще одна возможность загрузки связанных данных, так называемая Нетерпеливая загрузка. Вам решать, какую возможность использовать, но если вам нужна отложенная загрузка, как в вашем вопросе, у вас должна быть версия EF Core 2.1.

Yurii N. 02.10.2018 21:10

Другие вопросы по теме