优雅的linq解决方案,用于左连接和独特数据

时间:2012-02-10 15:50:34

标签: asp.net-mvc linq left-join unique

我想询问下面的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中,我使用以下查询在每个maplocation获取最早的预留,并且对于没有预订的任何位置都使用非null日期。

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 Query等效的内容

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 :(得分:0)

您将希望利用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)