我有以下三个生成的类,我正在尝试编写linq-to-sql查询以根据设置动态添加联接:
public class User
{
public int UserId { get; set; }
public string UserName { get; set; }
// ...
}
public class UserEmail
{
public int UserId { get; set; }
public string Address { get; set; }
// ...
}
public class UserPhone
{
public int UserId { get; set; }
public string PhoneNumber { get; set; }
// ...
}
这是针对数据库执行的理想选择,但我可以从连接表中检索所有列:
// If includeEmail and includePhone are both true.
SELECT u.*, ue.Address, up.PhoneNumber
FROM users u
JOIN user_email ue ON u.user_id = ue.user_id
JOIN user_phone up ON u.user_id = up.user_id
// If includeEmail and includePhone are both false.
SELECT u.*
FROM users u
这是我正在使用的代码:
// Base query
var queryableUsers = m_context.Users.Where(u => u.UserId == 1).Select(u => u);
// Join to other tables based on settings
if (includeEmail)
{
Expression<Func<UserEmails, UserEmails>> emailSelector = (ue => ue.Address);
queryableUsers = queryableUsers.Join(m_context.UserEmails, u => u.UserId, ue => ue.UserId).Select(emailSelector);
}
if (includePhone)
{
Expression<Func<UserPhones, UserPhones>> phoneSelector = (up => up.PhoneNumber);
queryableUsers = queryableUsers.Join(m_context.UserPhones, u => u.UserId, up => up.UserId).Select(phoneSelector);
}
// Execute query
var results = queryableUsers.ToList();
答案 0 :(得分:0)
您将面临的问题是您尝试更改queryableUsers
的类型。基本上你正在尝试:
IQueryable<User> queryableUsers = originalQuery;
if(includeEmail)
queryableUsers = IQueryable<UserEmails>;
if(includePhone)
queryableUsers = IQueryable<UserPhones>;
我不知道您的具体情况,但您可能甚至不需要决定何时包含一个或另一个(这可能是一个非常快速的查询,在这种情况下,首选清晰度和易用性)并且只是查询如下:
var userData = (from u in m_context.Users
where u.UserId == 1
select new
{
User = u,
EmailAddress = u.UserEmail.Address,
PhoneNumber = u.UserPhone.PhoneNumber
}).ToList();
或者,如果您想直接使用实体,可以在必要时使用DataLoadOptions急切加载相关实体:
DataLoadOptions options = new DataLoadOptions();
if(includeEmail)
options.LoadWith<User>(u => u.UserEmail);
m_context.LoadOptions = options;
var userData = m_context.Users.Where(u => u.Id == 1)
.ToList();
foreach(var user in userData)
{
// If includeEmail == true, then this will not trigger another db call
// If includeEmail == false, then the UserEmail property will be lazily
// loaded and another db call will be made for every iteration of this
// loop (very bad).
Console.WriteLine(user.UserEmail.Address);
}