Home > Blockchain >  Multiple implementations of the query pattern were found for source type 'DbSet<>'.
Multiple implementations of the query pattern were found for source type 'DbSet<>'.

Time:11-30

public List<ClassParticipantViewModel> GetClassParticipants(string studentId)
{
    List<ClassParticipantViewModel> list = new List<ClassParticipantViewModel>();

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

Join error:

enter image description here

Models:

enter image description here

ViewModel:

enter image description here

I'm developing a Web API using .NET Core 3.0 then I got an error stating that Ambiguous call to 'Join', this code is worked in my other projects. I'm confused if what is wrong, does the naming convention of my models have an effect?

CodePudding user response:

Quick intro to navigation props in EF:

If your classes looked like:

class Class {
  ICollection<ClassParticipant> ClassParticipants {get; set;}
  ...
}
class ClassParticipant {
  Class Class{get;set;}
  Participant Participant{get;set;}
  ...
}
class Participant{
  ICollection<ClassParticipant> ParticipantClasses {get; set;}
  ...
}

EF would be able to work out that this is a typical 1:M:1 relationship between classes:classparticipants:participants - many classes have many participants and the middle table breaks it down.

Once you've done that property mapping, you can write queries like:

_DbContext.ClassParticipants.Select(cp =>
   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 will see you navigating around in the select (cp.Class.ClassId), and know it has to join Classes in to get the data you want. You can also make direct navigational references in a similar way in a Where clause to load the related data, or, if you know you won't refer to the related data in the Select or Where, but you will want the data to be loaded so you can later refer to it in C#, you can use Include:

_DbContext.ClassParticipants.Include(cp => cp.Class).ToList();

footnote, you might want to have e.g. ICollection<ClassParticipant> ClassParticipants {get; set;} = new HashSet<ClassParticipant>(); because it makes creating new entities easier, not having to remember to make the collection first:

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 });
  • Related