Błąd przy zapytaniu LINQ

0

Witam,

Mój problem polega na tym że nie mogę pojąc dlaczego otrzymuję błąd z kodu pokazanego poniżej, gdyz z góry wydaje sie że jest wszystko ok:

 
public List<ClassroomViewModel> GetClassrooms(int TypeSchool)
        {
            using (var db = this.context.CreateNew())
            {
                var guery = db.Classrooms
                    .Where(x => x.UserId == this.UserId && x.TypeSchool == TypeSchool)
                    .Select(x => new ClassroomViewModel
                    {
                        Classroom_Id = x.Classroom_Id,
                        Name = x.Name,
                        ShortName = x.ShortName,
                        Capacity = x.Capacity,
                        Subject = x.Subject_Id == null ? null : subjects.GetSubjectById((int)x.Subject_Id) // w tym miejscu wyswietla sie bład
                    }).ToList();

                return guery;
            }
        }

Ten bład otrzymuje z kodu powyżej
Unable to create a null constant value of type 'zaplanuj.eu.Areas.Generator.Models.SchoolData.SubjectViewModel'. Only entity types, enumeration types or primitive types are supported in this context.

A ten gdy do Subject przypiszę na sztywno null
Unable to create a null constant value of type 'zaplanuj.eu.Areas.Generator.Models.SchoolData.SubjectViewModel'. Only entity types, enumeration types or primitive types are supported in this context.

gdy do zmiennej Subject stworze nowy obiekt i przypisze mu go na sztywno wszystko jest w porządku, problem jest wtedy gdy do zmiennej przypisuje warunek taki jak powyżej w kodzie, także wtedy gdy na sztywno dam "Subject = null" bądź samą metodę "Subject = subjects.GetSubjectById(1014)". Nie wiem co jest grane i w czym tkwi problem, podejrzewam że chodzi o mały szczegół którego nie mogę dojrzeć, dziwi mnie bardzo to że gdy na sztywno przypisze null też jest błąd co całkowicie mnie zbija z tropu.

Poniżej dalsza cześć kodu potrzebna do analizy:

    public class ClassroomViewModel
    {
        [HiddenInput(DisplayValue = false)]
        public int Classroom_Id { get; set; }

        [Required]
        [Display(Name = "Nazwa")]
        [StringLength(30)]
        public string Name { get; set; }

        [Required]
        [Display(Name = "Skrót")]
        [StringLength(10)]
        public string ShortName { get; set; }

        [Required]
        [Display(Name = "Pojemność klasy")]
        [Range(1, 999, ErrorMessage="Pojemność twojej klasy jest niepoprawna")]
        public int Capacity { get; set; }

        [Display(Name = "Przeznaczenie klasy")]
        public SubjectViewModel Subject { get; set; }

        [Display(Name = "Lista przedmiotów")]
        public List<SubjectViewModel> Subejcts { get; set; }
    }
    public class SubjectViewModel
    {
        [HiddenInput(DisplayValue = false)]
        public int Subject_Id { get; set; }

        [Required]
        [Display(Name = "Nazwa")]
        [StringLength(30)]
        public string Name { get; set; }

        [Required]
        [Display(Name = "Skrót")]
        [StringLength(10)]
        public string ShortName { get; set; }

        [Display(Name = "Opiekun grupy")]
        public bool GroupLeader { get; set; }
    }

Metoda zwracająca odpowiedni subject:

public SubjectViewModel GetSubjectById(int Subject_Id)
        {
            using (var db = this.context.CreateNew())
            {
                var guery = db.Subjects
                    .Where(x => x.Subject_Id == Subject_Id)
                    .Select(x => new SubjectViewModel
                    {
                        Subject_Id = x.Subject_Id,
                        Name = x.Name,
                        ShortName = x.ShortName,
                        GroupLeader = x.GroupLeader
                    }).SingleOrDefault();

                return guery;
            }
        }

W razie potrzeby dodaję tez model z EF

        public Classrooms()
        {
            this.Subjects1 = new HashSet<Subjects>();
        }
    
        public int Classroom_Id { get; set; }
        public int UserId { get; set; }
        public int TypeSchool { get; set; }
        public string Name { get; set; }
        public string ShortName { get; set; }
        public int Capacity { get; set; }
        public Nullable<int> Subject_Id { get; set; }
    
        public virtual Subjects Subjects { get; set; }
    }
1

Nie możesz mieszać sql i kodu wykonywanego po stronie C#.

  • Albo wszystko wykonujesz po stronie sql, czyli w linq występują tylko funkcje, które EF albo inny ORM wie jak przetłumaczyć na sql, np. z klasy SQLFunctions,
  • albo wszystko wykonujesz po stronie C#, co wiąże się z pobieraniem mnóstwa nadmiarowych danych,
  • albo robisz co się tylko da po stronie sql, a potem odbierasz dane z mssql i obrabiasz dalej po stronie C#.
0

No ok więc wymyśliłem coś takiego, lecz czemu nie chce zadziałać tutaj SingleOrDefalt i czy jeżeli nie zwróci żadnej wartości prawidłowo do zmiennej Subject Przypisze null?
Pierwszy czas mam do czynienia z takim powiązanym zapytaniem LINQ, czy to jest zrobione teraz poprawnie? A może da się to zrobić poprawniej?

public List<ClassroomViewModel> GetClassrooms(int TypeSchool)
        {
            using (var db = this.context.CreateNew())
            {
                var guery = db.Classrooms
                    .Where(x => x.UserId == this.UserId && x.TypeSchool == TypeSchool)
                    .Select(x => new ClassroomViewModel
                    {
                        Classroom_Id = x.Classroom_Id,
                        Name = x.Name,
                        ShortName = x.ShortName,
                        Capacity = x.Capacity,
                        Subject = db.Subjects.Where(y => y.Subject_Id == x.Subject_Id).Select(y => new SubjectViewModel { Subject_Id = y.Subject_Id, Name = y.Name, ShortName = y.ShortName, GroupLeader = y.GroupLeader }).FirstOrDefault()
                    }).ToList();

                return guery;
            }
        }
1

To nie jest zapytanie LINQ, to jest Extension Methods. Na samym LINQ przypomina to dość mocno zapytanie SQL. Poniżej przykładowe zapytanie:

	 from a in db.ActiveSessions
	 join l in db.Licences on a.LicenceId equals l.Id
	 where a.Id == sessionId
	 select new { Licence = l, Session = a }

Tak, jeśli nie będzie powiązanych danych w drugiej tabeli Subject będzie miało wartość null - przecież tak działa FirstOrDefault. Dlaczego nie działa SingleOrDefault - sprawdź w treści otrzymanego wyjątku.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.