AppBox升级进行时 - Any与All的用法(Entity Framework)
AppBox 是基于 FineUI 的通用权限管理框架,包括用户管理、职称管理、部门管理、角色管理、角色权限管理等模块。
属于某个角色的用户列表(Any的用法)
使用Subsonic,我们有两种方法获取属于某个角色的用户列表,分别是表关联和子查询。
Subsonic的表关联实现:
// 查询 X_User 表
SqlQuery q = new Select().From<XUser>().InnerJoin(XRoleUser.UserIdColumn, XUser.IdColumn);
q.Where("1").IsEqualTo("1"); // 在用户名称中搜索
string searchText = ttbSearchUser.Text.Trim();
if (!String.IsNullOrEmpty(searchText))
{
q.And(XUser.NameColumn).ContainsString(searchText);
} // 过滤选中角色下的所有用户
object[] values = Grid1.DataKeys[Grid1.SelectedRowIndexArray[0]];
int roleId = Convert.ToInt32(values[0]);
q.And(XRoleUser.RoleIdColumn).IsEqualTo(roleId); // 在查询添加之后,排序和分页之前获取总记录数
// Grid1总共有多少条记录
Grid2.RecordCount = q.GetRecordCount(); // 排列
q.OrderBys.Add(GetSortExpression(Grid2, XUser.Schema)); // 数据库分页
q.Paged(Grid2.PageIndex + 1, Grid2.PageSize);
XUserCollection items = q.ExecuteAsCollection<XUserCollection>(); Grid2.DataSource = items;
Grid2.DataBind();
Subsonic的子查询实现:
// 查询 X_User 表
SqlQuery q = new Select().From<XUser>();
q.Where("1").IsEqualTo("1"); // 在用户名称中搜索
string searchText = ttbSearchUser.Text.Trim();
if (!String.IsNullOrEmpty(searchText))
{
q.And(XUser.NameColumn).ContainsString(searchText);
} // 过滤选中角色下的所有用户
object[] values = Grid1.DataKeys[Grid1.SelectedRowIndexArray[0]];
int roleId = Convert.ToInt32(values[0]);
SqlQuery subQ = new Select(XRoleUser.UserIdColumn).From<XRoleUser>().Where(XRoleUser.RoleIdColumn).IsEqualTo(roleId); q.And(XUser.IdColumn).In(subQ); // 在查询添加之后,排序和分页之前获取总记录数
// Grid1总共有多少条记录
Grid2.RecordCount = q.GetRecordCount(); // 排列
q.OrderBys.Add(GetSortExpression(Grid2, XUser.Schema)); // 数据库分页
q.Paged(Grid2.PageIndex + 1, Grid2.PageSize);
XUserCollection items = q.ExecuteAsCollection<XUserCollection>(); Grid2.DataSource = items;
Grid2.DataBind();
使用Entity Framework就不能从数据库的角度思考问题,而应该从实体类之间的关系考虑问题,具体的实现:
IQueryable<User> q = DB.Users; // 在用户名称中搜索
string searchText = ttbSearchUser.Text.Trim();
if (!String.IsNullOrEmpty(searchText))
{
q = q.Where(u => u.Name.Contains(searchText));
} // 过滤选中角色下的所有用户
object[] values = Grid1.DataKeys[Grid1.SelectedRowIndexArray[0]];
int roleId = Convert.ToInt32(values[0]);
q = q.Where(u => u.Roles.Any(r => r.ID == roleId)); // 在查询添加之后,排序和分页之前获取总记录数
Grid2.RecordCount = q.Count(); // 排列和分页
q = SortAndPage<User>(q, Grid2); Grid2.DataSource = q;
Grid2.DataBind();
这里用到了 Any 方法,可以这么理解:检索一些用户,只要用户的任意一个角色是roleId就可以。
来看下生成的SQL语句:
exec sp_executesql N'SELECT TOP (20)
[Project2].[ID] AS [ID],
[Project2].[Name] AS [Name],
[Project2].[Email] AS [Email],
[Project2].[Password] AS [Password],
[Project2].[Enabled] AS [Enabled],
[Project2].[Gender] AS [Gender],
[Project2].[ChineseName] AS [ChineseName],
[Project2].[EnglishName] AS [EnglishName],
[Project2].[Photo] AS [Photo],
[Project2].[QQ] AS [QQ],
[Project2].[CompanyEmail] AS [CompanyEmail],
[Project2].[OfficePhone] AS [OfficePhone],
[Project2].[OfficePhoneExt] AS [OfficePhoneExt],
[Project2].[HomePhone] AS [HomePhone],
[Project2].[CellPhone] AS [CellPhone],
[Project2].[Address] AS [Address],
[Project2].[Remark] AS [Remark],
[Project2].[IdentityCard] AS [IdentityCard],
[Project2].[Birthday] AS [Birthday],
[Project2].[TakeOfficeTime] AS [TakeOfficeTime],
[Project2].[LastLoginTime] AS [LastLoginTime],
[Project2].[CreateTime] AS [CreateTime],
[Project2].[DeptID] AS [DeptID]
FROM ( SELECT [Project2].[ID] AS [ID], [Project2].[Name] AS [Name], [Project2].[Email] AS [Email], [Project2].[Password] AS [Password], [Project2].[Enabled] AS [Enabled], [Project2].[Gender] AS [Gender], [Project2].[ChineseName] AS [ChineseName], [Project2].[EnglishName] AS [EnglishName], [Project2].[Photo] AS [Photo], [Project2].[QQ] AS [QQ], [Project2].[CompanyEmail] AS [CompanyEmail], [Project2].[OfficePhone] AS [OfficePhone], [Project2].[OfficePhoneExt] AS [OfficePhoneExt], [Project2].[HomePhone] AS [HomePhone], [Project2].[CellPhone] AS [CellPhone], [Project2].[Address] AS [Address], [Project2].[Remark] AS [Remark], [Project2].[IdentityCard] AS [IdentityCard], [Project2].[Birthday] AS [Birthday], [Project2].[TakeOfficeTime] AS [TakeOfficeTime], [Project2].[LastLoginTime] AS [LastLoginTime], [Project2].[CreateTime] AS [CreateTime], [Project2].[DeptID] AS [DeptID], row_number() OVER (ORDER BY [Project2].[Name] DESC) AS [row_number]
FROM ( SELECT
[Extent1].[ID] AS [ID],
[Extent1].[Name] AS [Name],
[Extent1].[Email] AS [Email],
[Extent1].[Password] AS [Password],
[Extent1].[Enabled] AS [Enabled],
[Extent1].[Gender] AS [Gender],
[Extent1].[ChineseName] AS [ChineseName],
[Extent1].[EnglishName] AS [EnglishName],
[Extent1].[Photo] AS [Photo],
[Extent1].[QQ] AS [QQ],
[Extent1].[CompanyEmail] AS [CompanyEmail],
[Extent1].[OfficePhone] AS [OfficePhone],
[Extent1].[OfficePhoneExt] AS [OfficePhoneExt],
[Extent1].[HomePhone] AS [HomePhone],
[Extent1].[CellPhone] AS [CellPhone],
[Extent1].[Address] AS [Address],
[Extent1].[Remark] AS [Remark],
[Extent1].[IdentityCard] AS [IdentityCard],
[Extent1].[Birthday] AS [Birthday],
[Extent1].[TakeOfficeTime] AS [TakeOfficeTime],
[Extent1].[LastLoginTime] AS [LastLoginTime],
[Extent1].[CreateTime] AS [CreateTime],
[Extent1].[DeptID] AS [DeptID]
FROM [dbo].[Users] AS [Extent1]
WHERE (N''admin'' <> [Extent1].[Name]) AND ( EXISTS (SELECT
1 AS [C1]
FROM [dbo].[RoleUsers] AS [Extent2]
WHERE ([Extent1].[ID] = [Extent2].[UserID]) AND ([Extent2].[RoleID] = @p__linq__0)
))
) AS [Project2]
) AS [Project2]
WHERE [Project2].[row_number] > 0
ORDER BY [Project2].[Name] DESC',N'@p__linq__0 int',@p__linq__0=1
go
EF生成的SQL语句是很复杂,我们来稍微简化一下(为了看清本质,去掉了排序,过滤以及返回字段的个数等):
exec sp_executesql N'SELECT [Project2].[ID] AS [ID], [Project2].[Name] AS [Name], [Project2].[Email] AS [Email], [Project2].[Password] AS [Password]
FROM ( SELECT
[Extent1].[ID] AS [ID],
[Extent1].[Name] AS [Name],
[Extent1].[Email] AS [Email],
[Extent1].[Password] AS [Password]
FROM [dbo].[Users] AS [Extent1]
WHERE (N''admin'' <> [Extent1].[Name]) AND ( EXISTS (SELECT
1 AS [C1]
FROM [dbo].[RoleUsers] AS [Extent2]
WHERE ([Extent1].[ID] = [Extent2].[UserID]) AND ([Extent2].[RoleID] = @p__linq__0)
))
) AS [Project2]',N'@p__linq__0 int',@p__linq__0=1
go
进一步简化:
exec sp_executesql N' SELECT
[Extent1].[ID] AS [ID],
[Extent1].[Name] AS [Name],
[Extent1].[Email] AS [Email],
[Extent1].[Password] AS [Password]
FROM [dbo].[Users] AS [Extent1]
WHERE (N''admin'' <> [Extent1].[Name]) AND ( EXISTS (SELECT
1 AS [C1]
FROM [dbo].[RoleUsers] AS [Extent2]
WHERE ([Extent1].[ID] = [Extent2].[UserID]) AND ([Extent2].[RoleID] = @p__linq__0)
))
',N'@p__linq__0 int',@p__linq__0=1
go
进一步简化:
SELECT
[Users].[ID] AS [ID],
[Users].[Name] AS [Name],
[Users].[Email] AS [Email],
[Users].[Password] AS [Password]
FROM [dbo].[Users] AS [Users]
WHERE EXISTS (SELECT
1 AS [C1]
FROM [dbo].[RoleUsers] AS [RoleUsers]
WHERE ([Users].[ID] = [RoleUsers].[UserID]) AND ([RoleUsers].[RoleID] = 1)
)
进一步简化:
SELECT
ID,
Name,
Email,
Password
FROM Users
WHERE EXISTS (SELECT
1
FROM RoleUsers
WHERE (Users.ID = RoleUsers.UserID) AND (RoleUsers.RoleID = 1)
)
最终,我们看到了Entity Framework使用子查询和 EXISTS 关键字来完成 Any 的操作。
当然,如果是我们自己写SQL,可以使用 IN 关键字来达到相同的效果:
SELECT
ID,
Name,
Email,
Password
FROM Users
WHERE ID IN (SELECT
UserID
FROM RoleUsers
WHERE (Users.ID = RoleUsers.UserID) AND (RoleUsers.RoleID = 1)
)
也可以使用关联查询达到相同的效果:
SELECT
ID,
Name,
Email,
Password
FROM Users
INNER JOIN RoleUsers
ON (Users.ID = RoleUsers.UserID) AND (RoleUsers.RoleID = 1)
幸运的是,我么只需要一个 Any 关键字就完成了这个稍微复杂的查询。
不属于某个角色的用户列表(All的用法)
类似的,查询不属于某个角色的用户列表(用来添加用户到某个角色的UI界面中),使用Subsonic也有两种方法,我们只看下子查询的方式:
SqlQuery q = new Select().From<XUser>();
q.Where("1").IsEqualTo("1"); // 在职务名称中搜索
string searchText = ttbSearchMessage.Text.Trim();
if (!String.IsNullOrEmpty(searchText))
{
q.And(XUser.NameColumn).ContainsString(searchText);
} // 排除已经属于本角色的用户
int currentRoleId = GetQueryIntValue("id");
SqlQuery subQ = new Select(XRoleUser.UserIdColumn).From<XRoleUser>().Where(XRoleUser.RoleIdColumn).IsEqualTo(currentRoleId); q.And(XUser.IdColumn).NotIn(subQ); // 在查询添加之后,排序和分页之前获取总记录数
Grid1.RecordCount = q.GetRecordCount(); // 排列
q.OrderBys.Add(GetSortExpression(Grid1, XUser.Schema)); // 数据库分页
q.Paged(Grid1.PageIndex + 1, Grid1.PageSize);
XUserCollection items = q.ExecuteAsCollection<XUserCollection>(); Grid1.DataSource = items;
Grid1.DataBind();
使用Entity Framework,我们只需借助 All 关键字就能简单实现:
IQueryable<User> q = DB.Users; // 在职务名称中搜索
string searchText = ttbSearchMessage.Text.Trim();
if (!String.IsNullOrEmpty(searchText))
{
q = q.Where(u => u.Name.Contains(searchText));
} // 排除已经属于本角色的用户
int currentRoleId = GetQueryIntValue("id");
q = q.Where(u => u.Roles.All(r => r.ID != currentRoleId)); // 在查询添加之后,排序和分页之前获取总记录数
Grid1.RecordCount = q.Count(); // 排列和分页
q = SortAndPage<User>(q, Grid1); Grid1.DataSource = q;
Grid1.DataBind();
可以简单的理解:检索一些用户,要保证这些用户的所有角色没有一个是currentRoleId。
去除分页和排序后,生成的SQL语句为:
exec sp_executesql N'SELECT
[Extent1].[ID] AS [ID],
[Extent1].[Name] AS [Name],
[Extent1].[Email] AS [Email],
[Extent1].[Password] AS [Password],
[Extent1].[Enabled] AS [Enabled],
[Extent1].[Gender] AS [Gender],
[Extent1].[ChineseName] AS [ChineseName],
[Extent1].[EnglishName] AS [EnglishName],
[Extent1].[Photo] AS [Photo],
[Extent1].[QQ] AS [QQ],
[Extent1].[CompanyEmail] AS [CompanyEmail],
[Extent1].[OfficePhone] AS [OfficePhone],
[Extent1].[OfficePhoneExt] AS [OfficePhoneExt],
[Extent1].[HomePhone] AS [HomePhone],
[Extent1].[CellPhone] AS [CellPhone],
[Extent1].[Address] AS [Address],
[Extent1].[Remark] AS [Remark],
[Extent1].[IdentityCard] AS [IdentityCard],
[Extent1].[Birthday] AS [Birthday],
[Extent1].[TakeOfficeTime] AS [TakeOfficeTime],
[Extent1].[LastLoginTime] AS [LastLoginTime],
[Extent1].[CreateTime] AS [CreateTime],
[Extent1].[DeptID] AS [DeptID]
FROM [dbo].[Users] AS [Extent1]
WHERE NOT EXISTS (SELECT
1 AS [C1]
FROM [dbo].[RoleUsers] AS [Extent2]
WHERE ([Extent1].[ID] = [Extent2].[UserID]) AND (([Extent2].[RoleID] = @p__linq__0) OR (CASE WHEN ([Extent2].[RoleID] <> @p__linq__0) THEN cast(1 as bit) WHEN ([Extent2].[RoleID] = @p__linq__0) THEN cast(0 as bit) END IS NULL))
)',N'@p__linq__0 int',@p__linq__0=1
go
最终简化为:
SELECT
ID,
Name,
Email,
Password
FROM Users
WHERE NOT EXISTS (SELECT
1
FROM RoleUsers
WHERE (ID = RoleUsers.UserID) AND ((RoleUsers.RoleID = 1) OR (CASE WHEN (RoleUsers.RoleID <> 1) THEN cast(1 as bit) WHEN (RoleUsers.RoleID = 1) THEN cast(0 as bit) END IS NULL))
)
按照我的理解,其中:
CASE WHEN (RoleUsers.RoleID <> 1) THEN cast(1 as bit) WHEN (RoleUsers.RoleID = 1) THEN cast(0 as bit) END IS NULL
类似于下面的判断:
RoleUsers.RoleID IS NULL
只是不知道为啥会生成这么令人费解的代码。因为如果 RoleUsers.RoleID为NULL的话,既不会走进第一个WHEN,也不会走进第二个WHEN,自然就是NULL IS NULL为true了。
下面简单写个SELECT来验证我的想法:
select CASE WHEN (null <> 1)
THEN cast(1 as bit)
WHEN (null = 1)
THEN cast(0 as bit)
END
注意,这个NULL<>1的结果是FALSE,NULL=1的结果也是FALSE,所以最终的结果才是NULL。
再来看一个简单的SELECT查询:

下载或捐赠AppBox
1. AppBox v2.1 是免费软件,免费提供下载:http://fineui.com/bbs/forum.php?mod=viewthread&tid=3788
2. AppBox v3.0 是捐赠软件,你可以通过捐赠作者来获取AppBox v3.0的全部源代码(http://fineui.com/donate/)。
日寇忘我之心不死,同志尚需警惕!纪念九一八。
AppBox升级进行时 - Any与All的用法(Entity Framework)的更多相关文章
- AppBox升级进行时 - 拥抱Entity Framework的Code First开发模式
AppBox 是基于 FineUI 的通用权限管理框架,包括用户管理.职称管理.部门管理.角色管理.角色权限管理等模块. 从Subsonic到Entity Framework Subsonic最早发布 ...
- AppBox升级进行时 - 扁平化的权限设计
AppBox 是基于 FineUI 的通用权限管理框架,包括用户管理.职称管理.部门管理.角色管理.角色权限管理等模块. AppBox v2.0中的权限实现 AppBox v2.0中权限管理中涉及三个 ...
- AppBox升级进行时 - Entity Framework的增删改查
AppBox 是基于 FineUI 的通用权限管理框架,包括用户管理.职称管理.部门管理.角色管理.角色权限管理等模块. Entity Framework新增数据 以新增用户为例,作为对比,先来看下使 ...
- AppBox升级进行时 - 关联表查询与更新(Entity Framework)
AppBox 是基于 FineUI 的通用权限管理框架,包括用户管理.职称管理.部门管理.角色管理.角色权限管理等模块. 关联表的查询操作 使用 Include 方法,我们可以在一次数据库查询中将关联 ...
- AppBox升级进行时 - 如何向OrderBy传递字符串参数(Entity Framework)
AppBox 是基于 FineUI 的通用权限管理框架,包括用户管理.职称管理.部门管理.角色管理.角色权限管理等模块. Entity Framework提供的排序功能 再来回顾一下上篇文章,加载用户 ...
- AppBox升级进行时 - Attach陷阱(Entity Framework)
AppBox 是基于 FineUI 的通用权限管理框架,包括用户管理.职称管理.部门管理.角色管理.角色权限管理等模块. Attach方法 前面我们已经多次使用Attach方法,上一次使用Attach ...
- 【视频教程】一步步将AppBox升级到Pro版
本系列教程分为上中下三部分,通过视频的形式讲解如何将基于FineUI(开源版)的AppBox v6.0一步一步升级FineUIPro(基础版). [视频教程]一步步将AppBox升级到Pro版(上)主 ...
- Entity Framework Core 1.1 升级通告
原文地址:https://blogs.msdn.microsoft.com/dotnet/2016/11/16/announcing-entity-framework-core-1-1/ 翻译:杨晓东 ...
- Entity framework在用于WCF时创建数据模型的问题
众所周知,WCF的传输对象,在创建时需要在类名上标识[DataContract]以及在属性上标识[DataMember],当我们在使用Entity framework时(不考虑Code first的情 ...
随机推荐
- 移动端web开发总结
前一个星期实战完一个PC端的基于HTML+CSS的项目,这几天则接触了移动端的开发,同样也是在HTML+CSS的基础上完成.虽然第一次接触移动端的开发,但在开发过程中,我也是按照PC端的开发步骤来进行 ...
- .html(),.text()和.val()的差异总结
.html(),.text(),.val()三种方法都是用来读取选定元素的内容:只不过.html()是用来读取元素的html内容(包括html标签),.text()用来读取元素的纯文本内容,包括其后代 ...
- AO安装需要Microsoft Visual Studio 2013?
从接触ArcGIS9.2到 10.4,在不断升级的 过程中,既给我们带来了很多惊喜,也带来一些麻烦,因为ArcGIS版本不兼容.出于体验,安装了ArcGIS Desktop10.4,AO也得升到10. ...
- 破壳漏洞利用payload—shellshock in the wild
FireEye关于破壳漏洞(shellshock)在现实中的利用有一篇文章: shellshock in the wild 原文较长,进行了对CGI利用的详细分析,笔者比较感兴趣的是Shellshoc ...
- Objective-C 30分钟入门教程
Objective-C 30分钟入门教程 我第一次看OC觉得这个语言的语法有些怪异,为什么充满了@符号,[]符号,函数调用没有()这个,但是面向对象的高级语言也不外乎类,接口,多态,封装,继承等概念. ...
- 多行图片hover加边框兼容IE7+
问题: 遇到多行多列排列的图片时,hover上去加边框会把下面的图片挤到别处 ============================================================ ...
- 在执行xp_cmdshell的过程中出错,调用'LogonUserW'失败,错误代码:'1909'
在上篇文章Could not obtain information about Windows NT group/user 'xxxx\xxxx', error code 0x5里面,我介绍了SQL ...
- React 性能优化总结
初学者对React可能满怀期待,觉得React可能完爆其它一切框架,甚至不切实际地认为React可能连原生的渲染都能完爆--对框架的狂热确实会出现这样的不切实际的期待.让我们来看看React的官方是怎 ...
- Spark存储管理(读书笔记)
Spark存储管理(读书笔记) 转载请注明出处:http://www.cnblogs.com/BYRans/ Spark的存储管理 RDD的存放和管理都是由Spark的存储管理模块实现和管理的.本文从 ...
- iOS AppIcon尺寸和上传ITunes构建版本尺寸
避免忘记. 记录一下 App Icon: 29X2940X4058X5876X7687X8780X80120X120152X152167X167180X180 ITunes构建版本: 1242 x 2 ...