如何在 LINQ 中正确执行 LEFT JOIN?
How to do LEFT JOIN in LINQ correctly?
这是我的查询。我想在 LINQ
中执行此操作
SELECT tc.AppId,
tc.ConfigCode,
tc.ConfigId,
tc.ConfigType,
COALESCE(tm.ConfigValue, tc.ConfigValue) AS ConfigValue,
CASE
WHEN tc.ConfigType = 'Application'
THEN tc.AppId
ELSE tm.Id
END as Id,
FROM dbo.Configs tc
LEFT JOIN dbo.ConfigValues tm
ON tc.ConfigId = tm.ConfigId
这是我的查询,但我没有得到正确的结果
db.Configs
.Join(db.ConfigValues.DefaultIfEmpty(), tc => tc.ConfigId, tm => tm.ConfigId, (tc, tm) => new { tc = tc, tm = tm })
.Select(r => new {
AppId = (Guid?)r.tc.AppId,
ConfigCode = r.tc.ConfigCode,
ConfigId = r.tc.ConfigId,
ConfigValue = (r.tm.ConfigValue ?? r.tc.ConfigValue),
Id = (Guid)(r.tc.ConfigType == "Application" ? r.tc.AppId : r.tm.Id),
});
我认为您只是缺少 DefaultIfEmpty()。这 '?'在 r.tm?.ConfigValue??... 捕获 'r.tm'
的 NullPointer
db.Configs
.Join(db.ConfigValues.DefaultIfEmpty(), tc => tc.ConfigId, tm => tm.ConfigId, (tc, tm) => new { tc = tc, tm = tm })
.Select(r => new {
AppId = (Guid?)r.tc.AppId,
ConfigCode = r.tc.ConfigCode,
ConfigId = r.tc.ConfigId,
ConfigValue = (r.tm.ConfigValue ?? r.tc.ConfigValue),
Id = (Guid)(r.tc.ConfigType == "Application" ? r.tc.AppId : r.tm.Id)
}).DefaultIfEmpty(AppId = (Guid?)r.tc.AppId,
ConfigCode = r.tc.ConfigCode,
ConfigId = r.tc.ConfigId,
ConfigValue = (r.tm?.ConfigValue ?? r.tc.ConfigValue),
Id = (Guid)(r.tc.ConfigType == "Application" ? r.tc.AppId : r.tm.Id));
您的查询可能类似于
db.Configs
.LeftJoin(db.ConfigValues, tc => tc.ConfigId, tm => tm.ConfigId)
.Select(r => new {tc = r.Left, tm = r.Right})
.Select(r => new {
AppId = (Guid?)r.tc.AppId,
ConfigCode = r.tc.ConfigCode,
ConfigId = r.tc.ConfigId,
ConfigValue = (r.tm.ConfigValue ?? r.tc.ConfigValue),
Id = (Guid)(r.tc.ConfigType == "Application" ? r.tc.AppId : r.tm.Id),
});
如果您使用以下扩展方法。这将使您的代码在使用流畅版本的 LINQ 时更具可读性,并且可重用,因为您可以在其他 LINQ 查询中使用 LeftJoin/RightJoin。
public class LeftJoinResult
{
public TLeft Left { get; set; }
public TRight Right { get; set; }
}
public class RightJoinResult
{
public TRight Right { get; set; }
public TLeft Left { get; set; }
}
public static IQueryable> LeftJoin(this IQueryable left, IQueryable right, Expression> leftKeySelector, Expression> rightKeySelector)
where TRight : class
{
return left.GroupJoin(right, leftKeySelector, rightKeySelector, (l, r) => new
{
Left = l,
Matches = r.DefaultIfEmpty(),
})
.SelectMany(j => j.Matches, (j, m) => new LeftJoinResult
{
Left = j.Left,
Right = m,
});
}
public static IQueryable> RightJoin(this IQueryable right, IQueryable left, Expression> rightKeySelector, Expression> leftKeySelector)
where TLeft : class
{
return right.GroupJoin(left, rightKeySelector, leftKeySelector, (r, l) => new
{
Right = r,
Matches = l.DefaultIfEmpty(),
})
.SelectMany(j => j.Matches, (j, m) => new RightJoinResult
{
Right = j.Right,
Left = m,
});
}
这是我的查询。我想在 LINQ
中执行此操作SELECT tc.AppId,
tc.ConfigCode,
tc.ConfigId,
tc.ConfigType,
COALESCE(tm.ConfigValue, tc.ConfigValue) AS ConfigValue,
CASE
WHEN tc.ConfigType = 'Application'
THEN tc.AppId
ELSE tm.Id
END as Id,
FROM dbo.Configs tc
LEFT JOIN dbo.ConfigValues tm
ON tc.ConfigId = tm.ConfigId
这是我的查询,但我没有得到正确的结果
db.Configs
.Join(db.ConfigValues.DefaultIfEmpty(), tc => tc.ConfigId, tm => tm.ConfigId, (tc, tm) => new { tc = tc, tm = tm })
.Select(r => new {
AppId = (Guid?)r.tc.AppId,
ConfigCode = r.tc.ConfigCode,
ConfigId = r.tc.ConfigId,
ConfigValue = (r.tm.ConfigValue ?? r.tc.ConfigValue),
Id = (Guid)(r.tc.ConfigType == "Application" ? r.tc.AppId : r.tm.Id),
});
我认为您只是缺少 DefaultIfEmpty()。这 '?'在 r.tm?.ConfigValue??... 捕获 'r.tm'
的 NullPointerdb.Configs
.Join(db.ConfigValues.DefaultIfEmpty(), tc => tc.ConfigId, tm => tm.ConfigId, (tc, tm) => new { tc = tc, tm = tm })
.Select(r => new {
AppId = (Guid?)r.tc.AppId,
ConfigCode = r.tc.ConfigCode,
ConfigId = r.tc.ConfigId,
ConfigValue = (r.tm.ConfigValue ?? r.tc.ConfigValue),
Id = (Guid)(r.tc.ConfigType == "Application" ? r.tc.AppId : r.tm.Id)
}).DefaultIfEmpty(AppId = (Guid?)r.tc.AppId,
ConfigCode = r.tc.ConfigCode,
ConfigId = r.tc.ConfigId,
ConfigValue = (r.tm?.ConfigValue ?? r.tc.ConfigValue),
Id = (Guid)(r.tc.ConfigType == "Application" ? r.tc.AppId : r.tm.Id));
您的查询可能类似于
db.Configs
.LeftJoin(db.ConfigValues, tc => tc.ConfigId, tm => tm.ConfigId)
.Select(r => new {tc = r.Left, tm = r.Right})
.Select(r => new {
AppId = (Guid?)r.tc.AppId,
ConfigCode = r.tc.ConfigCode,
ConfigId = r.tc.ConfigId,
ConfigValue = (r.tm.ConfigValue ?? r.tc.ConfigValue),
Id = (Guid)(r.tc.ConfigType == "Application" ? r.tc.AppId : r.tm.Id),
});
如果您使用以下扩展方法。这将使您的代码在使用流畅版本的 LINQ 时更具可读性,并且可重用,因为您可以在其他 LINQ 查询中使用 LeftJoin/RightJoin。
public class LeftJoinResult
{
public TLeft Left { get; set; }
public TRight Right { get; set; }
}
public class RightJoinResult
{
public TRight Right { get; set; }
public TLeft Left { get; set; }
}
public static IQueryable> LeftJoin(this IQueryable left, IQueryable right, Expression> leftKeySelector, Expression> rightKeySelector)
where TRight : class
{
return left.GroupJoin(right, leftKeySelector, rightKeySelector, (l, r) => new
{
Left = l,
Matches = r.DefaultIfEmpty(),
})
.SelectMany(j => j.Matches, (j, m) => new LeftJoinResult
{
Left = j.Left,
Right = m,
});
}
public static IQueryable> RightJoin(this IQueryable right, IQueryable left, Expression> rightKeySelector, Expression> leftKeySelector)
where TLeft : class
{
return right.GroupJoin(left, rightKeySelector, leftKeySelector, (r, l) => new
{
Right = r,
Matches = l.DefaultIfEmpty(),
})
.SelectMany(j => j.Matches, (j, m) => new RightJoinResult
{
Right = j.Right,
Left = m,
});
}