#c# #.net
Вопрос:
public Listlt;ClassParticipantViewModelgt; GetClassParticipants(string studentId) { Listlt;ClassParticipantViewModelgt; list = new Listlt;ClassParticipantViewModelgt;(); var results = (from cp in _DbContext.ClassParticipants join c in _DbContext.Classes on cp.ClassId equals c.ClassId where cp.StudentId.Equals(studentId) select new ClassParticipantViewModel { //ClassParticipant ClassParticipantId = cp.ClassParticipantId, StudentId = cp.StudentId, ClassParticipantCreatedOn = cp.CreatedOn, //Class ClassId = c.ClassId, ClassCode = c.ClassCode, Section = c.Section, CourseCode = c.CourseCode, Description = c.Description, Units = c.Units, CreatedBy = c.CreatedBy, ClassCreatedOn = c.CreatedOn, }) .ToList(); list = list.Concat(results).ToList(); return list.ToList(); }
Ошибка соединения:
Модели:
Модель представления:
Я разрабатываю веб-API с использованием .NET Core 3.0, затем я получил сообщение об ошибке, в котором говорится, что неоднозначный вызов «Присоединиться», этот код работает в других моих проектах. Я в замешательстве, если что-то не так, влияет ли соглашение об именовании моих моделей?
Комментарии:
1. Судя по именам ваших сущностей, я ожидал бы, что между ними будут свойства навигации, что означало бы, что создание соединения вручную было бы ненужным.. Почему у класса нет, например
ICollectionlt;ClassParticipantgt; ClassParticipants {get;set;}
, а у участника класса естьClass Class{get;set;}
?2. @CaiusJard Как я могу присоединиться к этим двум, если создание соединения не требуется? Мне нужна подробная информация о классе, основанная на идентификаторе студента.
3. Инициализация
list
в первой строке метода является избыточной.4. @TsahiAsher Спасибо, исправлено, но все еще появляется неоднозначный вызов ошибки «Присоединиться».
5. Когда вы рассказали EF, как связаны два объекта (например, имея коллекцию участников класса в классе или имея класс в участнике класса), вы можете просто сказать
context.Classes.Include(c =gt;c.ClassParticipants)
, чтобы загрузить все классы и связанные с ними участники класса. Если вы используете связь в предложении where или select, она также автоматически присоединяется
Ответ №1:
Краткое введение в навигационные реквизиты в EF:
Если бы ваши занятия выглядели так:
class Class { ICollectionlt;ClassParticipantgt; ClassParticipants {get; set;} ... } class ClassParticipant { Class Class{get;set;} Participant Participant{get;set;} ... } class Participant{ ICollectionlt;ClassParticipantgt; ParticipantClasses {get; set;} ... }
EF смог бы понять, что это типичное соотношение 1:M:1 между классами:участники:участники — во многих классах много участников, и средняя таблица разбивает его.
После того, как вы выполнили сопоставление свойств, вы можете писать такие запросы, как:
_DbContext.ClassParticipants.Select(cp =gt; new ClassParticipantViewModel { //ClassParticipant ClassParticipantId = cp.ClassParticipantId, StudentId = cp.StudentId, ClassParticipantCreatedOn = cp.CreatedOn, //Class ClassId = cp.Class.ClassId, ClassCode = cp.Class.ClassCode, Section = cp.Class.Section, CourseCode = cp.Class.CourseCode, Description = cp.Class.Description, Units = cp.Class.Units, CreatedBy = cp.Class.CreatedBy, ClassCreatedOn = cp.Class.CreatedOn, } ).ToList();
EF увидит, как вы перемещаетесь в select ( cp.Class.ClassId
), и будет знать, что он должен присоединиться к классам, чтобы получить нужные вам данные. Вы также можете сделать прямые навигационные ссылки аналогичным образом в Where
предложении для загрузки связанных данных, или, если вы знаете , что не будете ссылаться на связанные данные в Select
или Where
, но захотите, чтобы данные были загружены, чтобы позже вы могли ссылаться на них в C#, вы можете использовать Include:
_DbContext.ClassParticipants.Include(cp =gt; cp.Class).ToList();
примечание, вы можете захотеть, например ICollectionlt;ClassParticipantgt; ClassParticipants {get; set;} = new HashSetlt;ClassParticipantgt;();
, потому, что это облегчает создание новых объектов, не забывая сначала создавать коллекцию:
var c = new Class(...); var p = new Participant(...); //can do this without having to remember to make a new collection c.ClassParticipants.Add(new ClassParticipant { Class = c, Participant = p });
Комментарии:
1. По моему опыту EF6, я бы настоятельно рекомендовал создать временную ссылку на
Class
, напримерlet c = cp.Class
, в запросе LINQ, а затем использоватьc.ClassId
и т. Д., В противном случае каждый вызовcp.Class....
будет добавлятьJOIN
оператор в сгенерированный SQL, снижая вашу производительность. Я не знаю, как это сделать в синтаксисе вызова метода.2. @TsahiAsher только что проверил это утверждение на EFCore 5 и не увидел никаких признаков того, что сейчас это так; для моих тестов создается и повторно используется одно СОЕДИНЕНИЕ
3. Тогда, может быть, они улучшили его в EFCore.