我有两个实体类User
和Connection
,而User
有一个Connection
的集合。
class User
{
public string username {get; set;}
public ICollection<Connection> Connections {get; set;}
}
class Connection
{
public string ConnectionId {get; set;}
public string RoomName {get; set;}
}
我有这个SQL Query,它检索用户的连接列表
// this code can be moved to the database as a stored procedure or view
var sql = @"SELECT Users.UserName, Users.UserPix,
Connections.ConnectionId, Connections.RoomName, Connections.DateCreated
FROM Users CROSS JOIN Connections
WHERE (Users.UserName = @p0) AND (Connections.RoomName = @p1)";
return _context.Users.SqlQuery(sql, username, roomName).FirstOrDefault();
它返回一个具有空连接列表的用户对象,而不是使用从数据库返回的数据填充连接。 我尝试用内连接替换交叉连接但仍然是相同的结果
我不知道如何修改sql查询以便返回实际数据。我怎么能这样做,或者有什么我想念的东西?
答案 0 :(得分:0)
为此,我首先检索/检查用户是否存在,然后检索他们的连接并将其添加到该用户的连接列表
public User GetUserAndConnections(string username, string roomname)
{
var user = _context.Users.Find(username);
if (user != null)
{
var connections =
_context.Users.Where(u => u.UserName == username)
.SelectMany(x => x.Connections.Where(p => p.RoomName == roomName))
.ToList();
user.AddExistingConnections(connections);
}
return user;
}
答案 1 :(得分:0)
由于您在这里没有做任何特别的事情(甚至没有任何投影),您可以直接从上下文返回实体,包括您想要的导航属性:
e.g。鉴于这些实体:
class User
{
public string username { get; set; }
public ICollection<Connection> Connections { get; set; }
}
class Connection
{
public string ConnectionId { get; set; }
public string RoomName { get; set; }
}
您的数据库中User - &gt;之间应存在一对多关系连接
为了获得特定用户的所有连接,或所有用户的所有连接,或者您可以在用户/连接上使用过滤器/聚合等来考虑的任何查询组合,同时保留关系,您只需使用{{1来自.Include()
QueryableExtensions
如果您有兴趣,签名也是如此:
System.Data.Entity
关于EF这是一件好事,您可以根据需要急切加载子实体,而不必弄乱实体设计或添加不包含导航属性的新实体类
所以基本上归结为:
public static IQueryable<T> Include<T, TProperty>(this IQueryable<T> source, Expression<Func<T, TProperty>> path) where T : class
不要忘记延期执行 - 如果您不知道延迟执行是什么,以及如何在EF中构建查询值得查看 - 一般的经验法则是;击中数据库的查询越少,您在C#中执行的操作越少(对于像聚合这样的数据库样式操作),您的应用程序的执行速度就越快 - 因此请确保您不必枚举结果,直到您完成为止。完全构建了查询,或者您将使用LINQ to对象在.NET端执行所有数字运算,而不是在SQL应该使用它!
所以调用using(YourDbContext context = new YourDbContext())
{
var query = context.Users.Include(user => user.Connections);
// Do stuff with query
}
或枚举上述查询会得到结果
EF会使用您选择的提供程序(可能是.ToList()
)将您所做的任何事情翻译成正确的SQL方言。你不需要编写任何SQL ......
您可能会执行的其他一些查询示例:
System.Data.SqlClient
这些都不需要你编写任何SQL - 在运行这些查询时放置SQL跟踪以查看EF的作用,并且通常它会比你更好地编写查询:)(只有在有时它不会通常当你做一些愚蠢的事情时)
修改强>
好的,我看到你试图过滤用户和通过线路返回的连接,在这种情况下,您需要显式加载导航属性作为单独的查询或使用投影进行过滤
e.g。
明确加载
// Get me users called Fred including their connection details
context.Users.Include(x => x.Connections).Where(u => u.Username == "Fred")
// Get me users that are currently connected to "Game Room"
context.Users.Include(x => x.Connections).Where(u => u.Connections.Any(c => c.RoomName == "Game Room")
这确实会产生两个查询
<强>投影强>
var user = context.Users.First(x => x.UserName == username);
context.Entry(user).Collection(x => x.Connections).Query().Where(x => x.RoomName == roomName).Load();
这会产生一个包含var usersConnections = context.Users
.Where(u => u.UserName == userName)
.Select(u => new
{
User = u,
Connections = u.Connections.Where(c => c.RoomName == roomName)
});
属性和User
属性的匿名类型。如果您需要通过某种域边界发送它,您也可以始终投射到已知类型
这将是针对数据源的单个查询