不相关实体变量的 Linq 子查询
Linq SubQuery for Unrelated entity variable
是否可以使用 Linq convert/duplicate 以下内容?
DECLARE @UserID INT = 1, @ViewerUserID INT = 1002;
SELECT UGR.*,
CASE
WHEN (
SELECT subR.[Level]
FROM UserGameRanks subUGR WITH (NOLOCK)
INNER JOIN Ranks subR WITH (NOLOCK) ON (subUGR.RankId = subR.Id)
INNER JOIN Games subG WITH (NOLOCK) ON (subUGR.GameId = subG.Id)
INNER JOIN Users subU WITH (NOLOCK) ON (subUGR.UserID = subU.Id)
WHERE subUGR.IsDeleted = 0 AND subU.Id = @ViewerUserID AND subUGR.GameID = UGR.GameId
) > R.[Level] THEN 1
ELSE 0
END AS CanEdit
FROM UserGameRanks UGR WITH (NOLOCK)
INNER JOIN Ranks R WITH (NOLOCK) ON (UGR.RankId = R.Id)
INNER JOIN Games G WITH (NOLOCK) ON (UGR.GameId = G.Id)
INNER JOIN Users U WITH (NOLOCK) ON (UGR.UserID = U.Id)
WHERE UGR.IsDeleted = 0 AND U.Id = @UserID
AND
(
(
(@ViewerUserID <> - 1)
AND
(UGR.VisibilityId = 1)
)
OR
(
(UGR.VisibilityId = 2)
)
OR
(
(UGR.VisibilityId = 0)
AND
(@UserID = @ViewerUserID)
)
)
特别是 CASE 子查询?我向用户实体 class 添加了一个 [NotMapped] CanEdit 值,但是我不确定如何用一个 sql 查询填充它,而不是先执行初始获取,然后循环遍历并更新 CanEdit .
我浏览了 Whosebug。
如有任何帮助,我们将不胜感激。
编辑:看了你的回答,我明白了怎么做,但我意识到我在问题中编造了一个东西。我最初创建上述查询作为我的问题的示例,但我现在发现它与我的问题没有直接关系。我更新了 SQL 部分...
我们的想法是,我们可能有很多排名,最低排名是 "Unset",这将是级别 0。所以如果我玩另一个用户玩的游戏并且我的排名设置在级别 2,我可以将此用户的排名分配给 1。但在不同的游戏中,我也可能是 "Unset"(级别 0),因此无法编辑 his/her 排名。
@CodingYoshi:这是我尝试过的
var viewerQuery = from ugr in context.UserGameRanks
join r in context.Ranks on ugr.RankId equals r.Id
join g in context.Games on ugr.GameId equals g.Id
join u in context.Users on ugr.UserId equals u.Id
where (!ugr.IsDeleted) && (ugr.UserId == viewerUserId)
select new { UserGameRank = ugr };
var query = from ugr in context.UserGameRanks
join r in context.Ranks on ugr.RankId equals r.Id
join g in context.Games on ugr.GameId equals g.Id
join u in context.Users on ugr.UserId equals u.Id
where (!ugr.IsDeleted) && (ugr.UserId == userId) &&
(
(viewerUserId != -1 && ugr.VisibilityId == Visibility.RegisteredUsers)
||
(ugr.VisibilityId == Visibility.Public)
||
(ugr.VisibilityId == Visibility.Hidden && userId == viewerUserId)
)
select new { GameName = g.Name, Username = ugr.Username, RankName = r.Name, CanEdit = (viewerQuery.Rank.Level > r.Level ? 1 : 0) };
也许是这样的:
var users = new List<User>
{
new User { Id = 1, UserName = "User1", UserTypeId = 1 },
new User { Id = 2, UserName = "User2", UserTypeId = 2 },
new User { Id = 3, UserName = "User3", UserTypeId = 2 },
};
var userTypes = new List<UserType>
{
new UserType { Id = 1, Type = "Admin", Security = 1 },
new UserType { Id = 2, Type = "User", Security = 2 }
};
var userId = 1;
var ViewerUserID = 2;
var viewerSecurity =
(from u in users
join ut in userTypes on u.UserTypeId equals ut.Id
where u.Id == ViewerUserID
select ut.Security).FirstOrDefault();
var res =
(from u in users
join ut in userTypes on u.UserTypeId equals ut.Id
where u.Id == userId || u.Id == -1
select new
{
Id = u.Id,
UserName = u.UserName,
CanEdit = viewerSecurity > ut.Security ? 1 : 0
});
}
class User {
public int Id {get; set;}
public string UserName {get; set;}
public int UserTypeId {get; set;}
}
class UserType {
public int Id {get; set;}
public string Type {get; set;}
public int Security {get; set;}
}
更新:
首先,无需编辑您的问题,因为其他人回答了您最初的问题,现在他们和我的最初回答毫无意义。 你应该开始一个新问题或更新这个问题。
这是您编辑的问题的代码:
var res =
(from ugr in userGameRanks
join r in ranks on ugr.RankId equals r.Id
join g in games on ugr.GameId equals g.Id
join u in users on ugr.UserId equals u.Id
where !ugr.IsDeleted // assuming IsDeleted is of type BIT in your DB
&& u.Id == userId
&& (
(ViewerUserID != -1 && ugr.VisibilityId == 1)
|| ugr.VisibilityId == 2
|| (ugr.VisibilityId == 0 && userId == ViewerUserID)
)
let level =
(from subUGR in userGameRanks
join subR in ranks on subUGR.RankId equals subR.Id
join subG in games on subUGR.GameId equals subG.Id
join subU in users on subUGR.UserId equals subU.Id
where !subUGR.IsDeleted
&& subU.Id == ViewerUserID
&& subUGR.GameId == ugr.GameId
select subR.Level).FirstOrDefault()
select new
{
ugr.RankId,
ugr.UserId,
ugr.GameId,
ugr.IsDeleted,
ugr.VisibilityId,
CanEdit = level > r.Level ? 1 : 0
});
希望对您有所帮助
我将数据库建模为 类 以使语法正确。不确定我是否做对了一切,但已经很接近了
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
int UserID = 1;
int ViewerUserID = 2;
DataBase db = new DataBase();
var resutls = (from subU in db.subU
join subUt in db.subUT on subU.Id equals subUt.UserTypeID
select new { subU = subU, subUt = subUt })
.Where(x => ((x.subU.Id == ViewerUserID) && (x.subUt.Security > x.subU.Security)) || x.subU.Id == -1)
.ToList();
}
}
public class DataBase
{
public List<Users> subU { get; set; }
public List<UserTypes> subUT { get; set; }
}
public class Users
{
public int Id { get; set; }
public int Security { get; set; }
}
public class UserTypes
{
public int UserTypeID { get; set; }
public int Security { get; set; }
}
}
几个问题:
1) 所有联接有什么用?您应该在模型配置中正确设置导航属性。
2) 结果查询的 CanEdit
属性 依赖于指定 viewerUserId
的游戏等级,但似乎指定 viewerUserId
是可选的。如果未指定或未找到查看器用户,默认行为是什么?我假设 CanEdit
应该是错误的。
public class YourResultClass()
{
public string GameName { get; set; }
public string UserName { get; set; }
public string RankName { get; set; }
public bool CanEdit { get; set; }
}
var targetUserGameRanksQuery = context.Users
.Where(u => !u.IsDeleted
&& u.UserId == userId)
// flatten for use in subsequent join
.SelectMany(u => u.UserGameRanks);
IQueryable<YourResultClass> query = null;
if(viewerUserId.HasValue)
{
var viewerGameRanksQuery = context.Users
.Where(u => !u.IsDeleted
&& u.UserId == viewerUserId)
// flatten for use in subsequent join
.SelectMany(u => u.UserGameRanks);
var joinQuery = targetUserGameRanksQuery // outer source `o`
.Join(viewerGameRanksQuery, // inner source `i`
o => o.GameId,
i => i.GameId,
(o, i) => new
{
GameName = o.Game.Name,
TargetUserName = o.Username,
TargetRankName = o.Rank.Name,
CanEdit = i.Rank.Level > o.Rank.Level,
Visibility = o.VisibilityId
});
query = joinQuery
.Where(at =>
at.Visibility == Visibility.RegisteredUsers
|| (at.Visibility == Visibility.Hidden
&& userId == viewerUserId.Value)
|| at.Visibility == Visibility.Public )
.Select(at =>
new YourResultClass()
{
GameName = at.GameName,
UserName = at.UserName,
RankName = at.RankName,
CanEdit = at.CanEdit,
});
}
else
{
query = targetUserGameRanksQuery
.Where(ugh => ugr.VisibilityId == Visibility.Public)
.Select(ugh => new YourResultClass()
{
GameName = ugr.Game.Name,
UserName = ugr.Username,
RankName = ugr.Rank.Name,
CanEdit = false,
});
}
是否可以使用 Linq convert/duplicate 以下内容?
DECLARE @UserID INT = 1, @ViewerUserID INT = 1002;
SELECT UGR.*,
CASE
WHEN (
SELECT subR.[Level]
FROM UserGameRanks subUGR WITH (NOLOCK)
INNER JOIN Ranks subR WITH (NOLOCK) ON (subUGR.RankId = subR.Id)
INNER JOIN Games subG WITH (NOLOCK) ON (subUGR.GameId = subG.Id)
INNER JOIN Users subU WITH (NOLOCK) ON (subUGR.UserID = subU.Id)
WHERE subUGR.IsDeleted = 0 AND subU.Id = @ViewerUserID AND subUGR.GameID = UGR.GameId
) > R.[Level] THEN 1
ELSE 0
END AS CanEdit
FROM UserGameRanks UGR WITH (NOLOCK)
INNER JOIN Ranks R WITH (NOLOCK) ON (UGR.RankId = R.Id)
INNER JOIN Games G WITH (NOLOCK) ON (UGR.GameId = G.Id)
INNER JOIN Users U WITH (NOLOCK) ON (UGR.UserID = U.Id)
WHERE UGR.IsDeleted = 0 AND U.Id = @UserID
AND
(
(
(@ViewerUserID <> - 1)
AND
(UGR.VisibilityId = 1)
)
OR
(
(UGR.VisibilityId = 2)
)
OR
(
(UGR.VisibilityId = 0)
AND
(@UserID = @ViewerUserID)
)
)
特别是 CASE 子查询?我向用户实体 class 添加了一个 [NotMapped] CanEdit 值,但是我不确定如何用一个 sql 查询填充它,而不是先执行初始获取,然后循环遍历并更新 CanEdit .
我浏览了 Whosebug。
如有任何帮助,我们将不胜感激。
编辑:看了你的回答,我明白了怎么做,但我意识到我在问题中编造了一个东西。我最初创建上述查询作为我的问题的示例,但我现在发现它与我的问题没有直接关系。我更新了 SQL 部分...
我们的想法是,我们可能有很多排名,最低排名是 "Unset",这将是级别 0。所以如果我玩另一个用户玩的游戏并且我的排名设置在级别 2,我可以将此用户的排名分配给 1。但在不同的游戏中,我也可能是 "Unset"(级别 0),因此无法编辑 his/her 排名。
@CodingYoshi:这是我尝试过的
var viewerQuery = from ugr in context.UserGameRanks
join r in context.Ranks on ugr.RankId equals r.Id
join g in context.Games on ugr.GameId equals g.Id
join u in context.Users on ugr.UserId equals u.Id
where (!ugr.IsDeleted) && (ugr.UserId == viewerUserId)
select new { UserGameRank = ugr };
var query = from ugr in context.UserGameRanks
join r in context.Ranks on ugr.RankId equals r.Id
join g in context.Games on ugr.GameId equals g.Id
join u in context.Users on ugr.UserId equals u.Id
where (!ugr.IsDeleted) && (ugr.UserId == userId) &&
(
(viewerUserId != -1 && ugr.VisibilityId == Visibility.RegisteredUsers)
||
(ugr.VisibilityId == Visibility.Public)
||
(ugr.VisibilityId == Visibility.Hidden && userId == viewerUserId)
)
select new { GameName = g.Name, Username = ugr.Username, RankName = r.Name, CanEdit = (viewerQuery.Rank.Level > r.Level ? 1 : 0) };
也许是这样的:
var users = new List<User>
{
new User { Id = 1, UserName = "User1", UserTypeId = 1 },
new User { Id = 2, UserName = "User2", UserTypeId = 2 },
new User { Id = 3, UserName = "User3", UserTypeId = 2 },
};
var userTypes = new List<UserType>
{
new UserType { Id = 1, Type = "Admin", Security = 1 },
new UserType { Id = 2, Type = "User", Security = 2 }
};
var userId = 1;
var ViewerUserID = 2;
var viewerSecurity =
(from u in users
join ut in userTypes on u.UserTypeId equals ut.Id
where u.Id == ViewerUserID
select ut.Security).FirstOrDefault();
var res =
(from u in users
join ut in userTypes on u.UserTypeId equals ut.Id
where u.Id == userId || u.Id == -1
select new
{
Id = u.Id,
UserName = u.UserName,
CanEdit = viewerSecurity > ut.Security ? 1 : 0
});
}
class User {
public int Id {get; set;}
public string UserName {get; set;}
public int UserTypeId {get; set;}
}
class UserType {
public int Id {get; set;}
public string Type {get; set;}
public int Security {get; set;}
}
更新: 首先,无需编辑您的问题,因为其他人回答了您最初的问题,现在他们和我的最初回答毫无意义。 你应该开始一个新问题或更新这个问题。
这是您编辑的问题的代码:
var res =
(from ugr in userGameRanks
join r in ranks on ugr.RankId equals r.Id
join g in games on ugr.GameId equals g.Id
join u in users on ugr.UserId equals u.Id
where !ugr.IsDeleted // assuming IsDeleted is of type BIT in your DB
&& u.Id == userId
&& (
(ViewerUserID != -1 && ugr.VisibilityId == 1)
|| ugr.VisibilityId == 2
|| (ugr.VisibilityId == 0 && userId == ViewerUserID)
)
let level =
(from subUGR in userGameRanks
join subR in ranks on subUGR.RankId equals subR.Id
join subG in games on subUGR.GameId equals subG.Id
join subU in users on subUGR.UserId equals subU.Id
where !subUGR.IsDeleted
&& subU.Id == ViewerUserID
&& subUGR.GameId == ugr.GameId
select subR.Level).FirstOrDefault()
select new
{
ugr.RankId,
ugr.UserId,
ugr.GameId,
ugr.IsDeleted,
ugr.VisibilityId,
CanEdit = level > r.Level ? 1 : 0
});
希望对您有所帮助
我将数据库建模为 类 以使语法正确。不确定我是否做对了一切,但已经很接近了
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
int UserID = 1;
int ViewerUserID = 2;
DataBase db = new DataBase();
var resutls = (from subU in db.subU
join subUt in db.subUT on subU.Id equals subUt.UserTypeID
select new { subU = subU, subUt = subUt })
.Where(x => ((x.subU.Id == ViewerUserID) && (x.subUt.Security > x.subU.Security)) || x.subU.Id == -1)
.ToList();
}
}
public class DataBase
{
public List<Users> subU { get; set; }
public List<UserTypes> subUT { get; set; }
}
public class Users
{
public int Id { get; set; }
public int Security { get; set; }
}
public class UserTypes
{
public int UserTypeID { get; set; }
public int Security { get; set; }
}
}
几个问题:
1) 所有联接有什么用?您应该在模型配置中正确设置导航属性。
2) 结果查询的 CanEdit
属性 依赖于指定 viewerUserId
的游戏等级,但似乎指定 viewerUserId
是可选的。如果未指定或未找到查看器用户,默认行为是什么?我假设 CanEdit
应该是错误的。
public class YourResultClass()
{
public string GameName { get; set; }
public string UserName { get; set; }
public string RankName { get; set; }
public bool CanEdit { get; set; }
}
var targetUserGameRanksQuery = context.Users
.Where(u => !u.IsDeleted
&& u.UserId == userId)
// flatten for use in subsequent join
.SelectMany(u => u.UserGameRanks);
IQueryable<YourResultClass> query = null;
if(viewerUserId.HasValue)
{
var viewerGameRanksQuery = context.Users
.Where(u => !u.IsDeleted
&& u.UserId == viewerUserId)
// flatten for use in subsequent join
.SelectMany(u => u.UserGameRanks);
var joinQuery = targetUserGameRanksQuery // outer source `o`
.Join(viewerGameRanksQuery, // inner source `i`
o => o.GameId,
i => i.GameId,
(o, i) => new
{
GameName = o.Game.Name,
TargetUserName = o.Username,
TargetRankName = o.Rank.Name,
CanEdit = i.Rank.Level > o.Rank.Level,
Visibility = o.VisibilityId
});
query = joinQuery
.Where(at =>
at.Visibility == Visibility.RegisteredUsers
|| (at.Visibility == Visibility.Hidden
&& userId == viewerUserId.Value)
|| at.Visibility == Visibility.Public )
.Select(at =>
new YourResultClass()
{
GameName = at.GameName,
UserName = at.UserName,
RankName = at.RankName,
CanEdit = at.CanEdit,
});
}
else
{
query = targetUserGameRanksQuery
.Where(ugh => ugr.VisibilityId == Visibility.Public)
.Select(ugh => new YourResultClass()
{
GameName = ugr.Game.Name,
UserName = ugr.Username,
RankName = ugr.Rank.Name,
CanEdit = false,
});
}