Элегантное решение linq для левых соединений с уникальными данными - PullRequest
0 голосов
/ 10 февраля 2012

Я хотел бы спросить, является ли мое решение Linq ниже хорошим решением или есть лучший способ. Я новичок в использовании Linq и наиболее знаком с MySQL. Итак, я конвертировал один из моих прошлых проектов из PHP в .NET MVC и пытаюсь выучить Linq. Я хотел бы узнать, есть ли лучшее решение, чем то, которое я придумал.

У меня есть следующие структуры таблиц:

CREATE TABLE maplocations (
    ID int NOT NULL AUTO_INCREMENT,
    name varchar(35) NOT NULL,
    Lat double NOT NULL,
    Lng double NOT NULL,
    PRIMARY KEY (ID),
    UNIQUE KEY name (name)
);

CREATE TABLE reservations (
    ID INT NOT NULL AUTO_INCREMENT,
    loc_ID INT NOT NULL,
    resDate DATE NOT NULL,
    user_ID INT NOT NULL,
    PRIMARY KEY (ID),
    UNIQUE KEY one_per (loc_ID, resDate),
    FOREIGN KEY (user_ID) REFERENCES Users (ID),
    FOREIGN KEY (loc_ID) REFERENCES MapLocations (ID)
);

CREATE TABLE Users (
    ID INT NOT NULL AUTO_INCREMENT,
    name VARCHAR(20) NOT NULL,
    email VARCHAR(50) NOT NULL,
    pass VARCHAR(128) NOT NULL,
    salt VARCHAR(5) NOT NULL,
    PRIMARY KEY (ID),
    UNIQUE KEY unique_names (name),
    UNIQUE KEY unique_email (email)
);

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

SELECT locs.*, if(res.resDate,res.resDate,'0001-01-01') as resDate, res.Name as User
FROM MapLocations locs
LEFT JOIN (
    SELECT loc_ID, resDate, Name 
    FROM Reservations, Users
    WHERE resDate >= Date(Now())
    AND user_ID = Users.ID
    ORDER BY resDate
) res on locs.ID = res.loc_ID
group by locs.ID
ORDER BY locs.Name;

В Linq, когда Visual Studio автоматически создает большую часть структуры после подключения к базе данных, я придумал следующий эквивалент этого SQL-запроса

var resList = (from res in Reservations
    where res.ResDate >= DateTime.Today
    select res);

var locAndRes = 
    (from loc in Maplocations 
    join res in resList on loc.ID equals res.Loc_ID into join1
    from res2 in join1.DefaultIfEmpty()
    join usr in Users on res2.User_ID equals usr.ID into join2
    from usr2 in join2.DefaultIfEmpty()
    orderby loc.ID,res2.ResDate
    select new {
            ID = (int)loc.ID,
            Name = (string)loc.Name,
            Lat = (double)loc.Lat,
            Lng = (double)loc.Lng,
            resDate = res2 != null ?(DateTime)res2.ResDate : DateTime.MinValue,
            user = usr2 != null ? usr2.Name : null
    }).GroupBy(a => a.ID).Select(b => b.FirstOrDefault());

Итак, мне интересно, есть ли лучший способ выполнить этот запрос? Это эквивалентно? Есть ли хорошие практики, которым я должен следовать?

Кроме того, еще один вопрос, у меня проблемы с получением этого из var в Список. делать что-то подобное не работает

List<locAndResModel> locList = locAndRes.AsQueryable().ToList<locAndResModel>();

В приведенном выше фрагменте locAndResModel - это просто класс, в котором есть переменные для соответствия int, string, double double, DateTime, строковых результатов запроса. Есть ли простой способ получить список без необходимости использовать foreach и передавать результаты в переопределение конструктора? Или мне просто добавить его в ViewData и вернуть View?

1 Ответ

0 голосов
/ 11 февраля 2012

Вы захотите воспользоваться автоматическими соединениями, выполняемыми Entity Framework. Попробуйте и дайте мне знать, если он делает то, что вы хотите:

var locAndRes = from maplocation in MapLocations
                let earliestReservationDate = maplocation.Reservations.Min(res => res.resDate) 
                let earliestReservation = (from reservation in mapLocation.Reservations
                                           where reservation.resDate == earliestReservationDate && reservation.resDate >= DateTime.Today
                                           select reservation).FirstOrDefault()
                select new locAndResModel( maplocation.ID, maplocation.name, maplocation.Lat, maplocation.Lng, earliestReservation != null ? earliestReservation.resDate : DateTime.MinValue, earliestReservation != null ?earliestReservation.User.name : null)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...