0

設定に基づいて結合を動的に追加するために、linq-to-sql クエリを作成しようとしている次の 3 つの生成されたクラスがあります。

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();
4

1 に答える 1

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);
}
于 2013-09-04T16:41:10.560 に答える