Запрос «многие ко многим» с Linq-To-NHibernate - PullRequest
0 голосов
/ 11 мая 2010

Хорошо, ребята (и девчонки), этот сводит меня с ума всю ночь, и я обращаюсь к вашей коллективной мудрости за помощью.

Я использую Fluent Nhibernate и Linq-To-NHibernate в качестве истории доступа к данным, и у меня есть следующая упрощенная структура БД:

CREATE TABLE [dbo].[Classes](
 [Id] [bigint] IDENTITY(1,1) NOT NULL,
 [Name] [nvarchar](100) NOT NULL,
 [StartDate] [datetime2](7) NOT NULL,
 [EndDate] [datetime2](7) NOT NULL,
 CONSTRAINT [PK_Classes] PRIMARY KEY CLUSTERED 
(
 [Id] ASC
)

CREATE TABLE [dbo].[Sections](
 [Id] [bigint] IDENTITY(1,1) NOT NULL,
 [ClassId] [bigint] NOT NULL,
 [InternalCode] [varchar](10) NOT NULL,
 CONSTRAINT [PK_Sections] PRIMARY KEY CLUSTERED 
(
 [Id] ASC
)

CREATE TABLE [dbo].[SectionStudents](
 [SectionId] [bigint] NOT NULL,
 [UserId] [uniqueidentifier] NOT NULL,
 CONSTRAINT [PK_SectionStudents] PRIMARY KEY CLUSTERED 
(
 [SectionId] ASC,
 [UserId] ASC
)

CREATE TABLE [dbo].[aspnet_Users](
 [ApplicationId] [uniqueidentifier] NOT NULL,
 [UserId] [uniqueidentifier] NOT NULL,
 [UserName] [nvarchar](256) NOT NULL,
 [LoweredUserName] [nvarchar](256) NOT NULL,
 [MobileAlias] [nvarchar](16) NULL,
 [IsAnonymous] [bit] NOT NULL,
 [LastActivityDate] [datetime] NOT NULL,
PRIMARY KEY NONCLUSTERED 
(
 [UserId] ASC
)

Для краткости я опустил внешние ключи, но по сути это сводится к:

  • В классе может быть много разделов.
  • Секция может принадлежать только одному классу, но может иметь много учеников.
  • Студент (aspnet_Users) может принадлежать ко многим разделам.

Я установил соответствующие классы Model и классы Fluent NHibernate Mapping, все это работает нормально.

Вот где я застреваю. Мне нужно написать запрос, который будет возвращать разделы, в которые зачислен учащийся, на основе идентификатора пользователя и даты проведения урока.

Вот что я пробовал до сих пор:

1

var sections = (from s in this.Session.Linq<Sections>()
where s.Class.StartDate <= DateTime.UtcNow
&& s.Class.EndDate > DateTime.UtcNow
&& s.Students.First(f => f.UserId == userId) != null
select s);

2.

var sections = (from s in this.Session.Linq<Sections>()
where s.Class.StartDate <= DateTime.UtcNow
&& s.Class.EndDate > DateTime.UtcNow
&& s.Students.Where(w => w.UserId == userId).FirstOrDefault().Id == userId
select s);

Очевидно, что приведенное выше 2 приведет к сбою, если не будет учеников, соответствующих идентификатору пользователя для классов с текущей датой между датами начала и окончания ... но я просто хотел попробовать.

Фильтры для Class StartDate и EndDate работают нормально, но отношения «многие ко многим» со студентами оказываются трудными. Каждый раз, когда я пытаюсь выполнить запрос, я получаю ArgumentNullException с сообщением:

Значение не может быть нулевым. Имя параметра: сессия

Я подумал о том, чтобы пойти по пути установления отношения SectionStudents с классом Model со ссылкой на Section и ссылкой на Student вместо многих ко многим. Я бы хотел этого избежать, если смогу, и я даже не уверен, что так будет.

Заранее спасибо всем, кто может помочь.

Ryan

1 Ответ

0 голосов
/ 13 мая 2010

Для всех, кого это волнует, похоже, что в будущем может сработать следующее, если Linq-To-NHibernate может поддерживать подзапросы (или я могу быть совершенно неосновным, и это может быть ограничением API Criteria, который используется Linq-To-NHibernate):

var sections = (from s in session.Linq<Section>()
where s.Class.StartDate <= DateTime.UtcNow
&& s.Class.EndDate > DateTime.UtcNow
&& s.Students.First(f => f.UserId == userId) != null
select s);

Однако в данный момент я получаю следующее исключение в LINQPad при выполнении этого запроса:

Невозможно использовать подзапросы по критериям без проекции.

Итак, пока я разделил это на 2 операции. Сначала получите Студента и соответствующие Разделы и затем отфильтруйте это к Дате класса. К сожалению, это приводит к 2 запросам к базе данных, но для моих целей это вполне подойдет.

...