我正在使用带有POCO和DbContext的Entity Framework 4.1,没有代理也没有延迟加载。
我是Entity Framework和LINQ的新手,但到目前为止,使用它的过程非常简单。 我有一些SQL的基本知识,并且首先构建了数据库,然后创建了模型。
我的问题涉及3个表格(我只留下相关内容):
CREATE TABLE [dbo].[Users](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](50) NULL
)
CREATE TABLE [dbo].[UserFriends](
[UserId] [int] NOT NULL,
[FriendId] [int] NOT NULL
)
CREATE TABLE [dbo].[UserStatuses](
[Id] [int] IDENTITY(1,1) NOT NULL,
[UserId] [int] NOT NULL,
[Message] [nvarchar](max) NOT NULL
)
PK是Usres.Id,UserStatuses.Id,UserFriends.UserId + UserFriends.FriendId。
UserId也是Users.Id的FK。
每个用户都可以拥有许多状态和很多朋友
我希望数据库结构清晰。
我要做的是获取一个朋友用户列表及其最新状态。
在SQL中,它看起来像:
SELECT * FROM Users U
OUTER APPLY
(
SELECT TOP 1 *
FROM UserStatuses
WHERE UserId = U.Id
ORDER BY Id DESC
) S
WHERE U.Id IN (SELECT FriendId FROM UserFriends WHERE UserId = 5)
这将使所有朋友获得'5'及其最新状态消息。 我认为这是最有效的方式(对朋友和用户进行内部联接以及对状态消息进行外部联接),但这不是问题。
我想使用实体框架来做到这一点。 我发现了如何获得我的朋友列表:
var friends = db.UserFriends.Where(f => f.FriendId.Equals(userId)).Select(f => f.User);
但如果我要添加.Include(u => u.UserStatuses)来获取状态,我会得到所有这些,我想只返回最新的。
为了让它发挥作用,我唯一能做的就是:
var friends = db.UserFriends.Where(f => f.FriendId.Equals(userId)).Select(f => f.User);
foreach (Model.User friend in friends)
{
db.Entry(friend).Collection(f => f.UserStatuses).Query().OrderByDescending(s => s.Id).Take(1).Load();
}
但现在发生的是,对于每个朋友,我都会向数据库生成另一个SQL查询,这似乎是(非常)糟糕的做法。
如何在单个查询中实现? 非常感谢有关如何加载最新插入的相关实体的任何建议。
谢谢,
答案 0 :(得分:1)
在单个数据库查询中获取此功能的唯一方法是投影:
var friendsWithLastStatus = db.UserFriends
.Where(f => f.FriendId.Equals(userId))
.Select(f => new
{
User = f.User,
LastStatus = f.User.UserStatuses
.OrderByDescending(s => s.Id).FirstOrDefault()
})
.ToList();
这为您提供了一个匿名类型对象列表,其中每个条目都具有User
属性,LastStatus
属性具有该用户的最新状态。
如果您愿意,可以投射到命名类型:
public class UserWithLastStatus
{
public User User { get; set; }
public UserStatus LastStatus { get; set; }
}
然后在new ...
上面的new UserWithLastStatus ...
中将List<UserWithLastStatus>
替换为{{1}}作为查询的结果类型。