【问题标题】:Adding joins and selects to a linq-to-sql lambda expression将连接和选择添加到 linq-to-sql lambda 表达式
【发布时间】:2013-09-04 15:38:48
【问题描述】:

我有以下三个生成的类,我正在尝试编写一个 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();

【问题讨论】:

  • 你的结果应该是List&lt;User&gt;。但是User 没有邮件和电话的属性。因此,您仍然只返回来自用户的数据。选择不会改变
  • 对,我知道我的代码不正确,只是想让您了解我要做什么。基本上我正在尝试返回以下对象,但不知道如何引用我在选择中未执行子查询而添加的联接:new { User = u, Address = u.UserEmailList.Where(ue => ue.UserId == u.User_id).Select(ue => ue.Address).FirstOrDefault(), PhoneNumber = u.UserPhoneList.Where(up => up.UserId == u.UserId).Select(up => up.PhoneNumber ).FirstOrDefault() }

标签: c# sql linq linq-to-sql lambda


【解决方案1】:

您将面临的问题是您试图更改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);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多