EF5.x Code First 一对多关联条件查询,Contains,Any,All
背景
通过多个部门id获取所有用户,部门和用户是多对多。
已知部门id,获取该部门包括该部门下的所有子部门的所有用户。
关系如下:
public class Entity:IEntity { public Guid Id { get; set; } public string CreateUser { get; set; } public DateTime CreateTime { get; set; } public string ModifyUser { get; set; } public DateTime? ModifyTime { get; set; } [Timestamp] public Byte[] RowVersion { get; set; } } //组织架构 public class WMS_Org : Entity { public WMS_Org() { } public string OrgName { get; set; } public string OrgDesc { get; set; } public int OrgOrder { get; set; } public string OrgFatherId { get; set; } public virtual ICollection<WMS_OrgUser> OrgUserIds { get; set; } } //用户 public class WMS_User : Entity { public WMS_User() { } public string UserName { get; set; } public string NickName { get; set; } public string UserPwd { get; set; } public string Sex { get; set; } public string Phone { get; set; } public string Email { get; set; } public string QQ { get; set; } public string Address { get; set; } public string Remark { get; set; } public virtual ICollection<WMS_OrgUser> UserOrgIds { get; set; } } //组织架构和用户的关联 public class WMS_OrgUser : Entity { public WMS_OrgUser() { } public Guid OrgId { get; set; } [ForeignKey("OrgId")] public virtual WMS_Org Org { get; set; } public Guid UserId { get; set; } [ForeignKey("UserId")] public virtual WMS_User User { get; set; } }
已知组织的id
如上图,我单击0100组织架构,要获取该组织架构下的所有用户,首先由于用户是挂载到每个节点上的,所有需要事先遍历获取所有的子节点获取节点的id
放到Guid[]数组里
提交后台查询
//DBSET=DbSet<WMS_User>,ids=Guid[] ids参数 //第一种方式All DBSET.Where(p => p.UserOrgIds.All(o=>ids.Contains(o.OrgId))); //第二种方式Any DBSET.Where(p => p.UserOrgIds.Any(o=>ids.Contains(o.OrgId)));
注意EF采用Contains构造in的sql语句
很直观的可以看出两个区别,一个是All,一个Any,那么产生的sql有什么区别呢?
//All,EF产生的是inner Join
SELECT [Extent1].[Id] AS [Id], [Extent1].[UserName] AS [UserName], [Extent1].[NickName] AS [NickName], [Extent1].[UserPwd] AS [UserPwd], [Extent1].[Sex] AS [Sex], [Extent1].[Phone] AS [Phone], [Extent1].[Email] AS [Email], [Extent1].[QQ] AS [QQ], [Extent1].[Address] AS [Address], [Extent1].[Remark] AS [Remark], [Extent1].[Disable] AS [Disable], [Extent1].[CreateUser] AS [CreateUser], [Extent1].[CreateTime] AS [CreateTime], [Extent1].[ModifyUser] AS [ModifyUser], [Extent1].[ModifyTime] AS [ModifyTime], [Extent1].[RowVersion] AS [RowVersion] FROM [dbo].[WMS_User] AS [Extent1] WHERE NOT EXISTS ( SELECT 1 AS [C1] FROM [dbo].[WMS_OrgUser] AS [Extent2] WHERE ([Extent1].[Id] = [Extent2].[UserId]) AND ( ( NOT ( [Extent2].[OrgId] IN (CAST('4e108b91-be3c-4cf4-a074-3767b9b8c7dc' AS UNIQUEIDENTIFIER), CAST('1cc15f8c-3758-47d3-862a-5287ab5d0651' AS UNIQUEIDENTIFIER), CAST('e1bf6f5a-800a-4fd4-9309-576c1d84ba2f' AS UNIQUEIDENTIFIER), CAST('a436b8a9-4b3a-4bf9-bbdd-839571e03915' AS UNIQUEIDENTIFIER), CAST('b0d6aead-e72f-4fd5-b2cd-e575454d3a4c' AS UNIQUEIDENTIFIER)) ) ) OR ( CASE WHEN ( [Extent2].[OrgId] IN ( CAST('4e108b91-be3c-4cf4-a074-3767b9b8c7dc' AS UNIQUEIDENTIFIER), CAST('1cc15f8c-3758-47d3-862a-5287ab5d0651' AS UNIQUEIDENTIFIER), CAST('e1bf6f5a-800a-4fd4-9309-576c1d84ba2f' AS UNIQUEIDENTIFIER), CAST('a436b8a9-4b3a-4bf9-bbdd-839571e03915' AS UNIQUEIDENTIFIER), CAST('b0d6aead-e72f-4fd5-b2cd-e575454d3a4c' AS UNIQUEIDENTIFIER)) ) THEN CAST(1 AS BIT) WHEN ( NOT ( [Extent2].[OrgId] IN ( CAST('4e108b91-be3c-4cf4-a074-3767b9b8c7dc' AS UNIQUEIDENTIFIER), CAST('1cc15f8c-3758-47d3-862a-5287ab5d0651' AS UNIQUEIDENTIFIER), CAST('e1bf6f5a-800a-4fd4-9309-576c1d84ba2f' AS UNIQUEIDENTIFIER), CAST('a436b8a9-4b3a-4bf9-bbdd-839571e03915' AS UNIQUEIDENTIFIER), CAST('b0d6aead-e72f-4fd5-b2cd-e575454d3a4c' AS UNIQUEIDENTIFIER)) ) ) THEN CAST(0 AS BIT) END IS NULL ) ) )
//Any方式,EF生成的Exists SELECT [Extent1].[Id] AS [Id], [Extent1].[UserName] AS [UserName], [Extent1].[NickName] AS [NickName], [Extent1].[UserPwd] AS [UserPwd], [Extent1].[Sex] AS [Sex], [Extent1].[Phone] AS [Phone], [Extent1].[Email] AS [Email], [Extent1].[QQ] AS [QQ], [Extent1].[Address] AS [Address], [Extent1].[Remark] AS [Remark], [Extent1].[CreateUser] AS [CreateUser], [Extent1].[CreateTime] AS [CreateTime], [Extent1].[ModifyUser] AS [ModifyUser], [Extent1].[ModifyTime] AS [ModifyTime], [Extent1].[RowVersion] AS [RowVersion] FROM [dbo].[WMS_User] AS [Extent1] WHERE EXISTS (SELECT 1 AS [C1] FROM [dbo].[WMS_OrgUser] AS [Extent2] WHERE ([Extent1].[Id] = [Extent2].[UserId]) AND ([Extent2].[OrgId] IN (cast('bd3c010c-476f-45e6-8d83-ad741cc55309' as uniqueidentifier), cast('4e108b91-be3c-4cf4-a074-3767b9b8c7dc' as uniqueidentifier), cast('1cc15f8c-3758-47d3-862a-5287ab5d0651' as uniqueidentifier), cast('e1bf6f5a-800a-4fd4-9309-576c1d84ba2f' as uniqueidentifier), cast('a436b8a9-4b3a-4bf9-bbdd-839571e03915' as uniqueidentifier), cast('b0d6aead-e72f-4fd5-b2cd-e575454d3a4c' as uniqueidentifier), cast('79ddb55a-1587-4928-a312-58da0c091459' as uniqueidentifier), cast('618de87e-2d97-4c0a-b6c1-acd072c305e2' as uniqueidentifier))) )
也就是说All是包括条件和不在条件之内的任何值,而Any是严格在条件之内的值,但其实我们想要的是Inner Join的方式,相当于是懒加载方式,那么需要加上Include,也就是
IQueryable<WMS_OrgUser> test5 = _db.wmsOrgUser.Include("User").Where(p => ids.Contains(p.OrgId));
SELECT 1 AS [C1], [Extent1].[Id] AS [Id], [Extent1].[OrgId] AS [OrgId], [Extent1].[UserId] AS [UserId], [Extent1].[CreateUser] AS [CreateUser], [Extent1].[CreateTime] AS [CreateTime], [Extent1].[ModifyUser] AS [ModifyUser], [Extent1].[ModifyTime] AS [ModifyTime], [Extent1].[RowVersion] AS [RowVersion], [Extent2].[Id] AS [Id1], [Extent2].[UserName] AS [UserName], [Extent2].[NickName] AS [NickName], [Extent2].[UserPwd] AS [UserPwd], [Extent2].[Sex] AS [Sex], [Extent2].[Phone] AS [Phone], [Extent2].[Email] AS [Email], [Extent2].[QQ] AS [QQ], [Extent2].[Address] AS [Address], [Extent2].[Remark] AS [Remark], [Extent2].[Disable] AS [Disable], [Extent2].[CreateUser] AS [CreateUser1], [Extent2].[CreateTime] AS [CreateTime1], [Extent2].[ModifyUser] AS [ModifyUser1], [Extent2].[ModifyTime] AS [ModifyTime1], [Extent2].[RowVersion] AS [RowVersion1] FROM [dbo].[WMS_OrgUser] AS [Extent1] INNER JOIN [dbo].[WMS_User] AS [Extent2] ON [Extent1].[UserId] = [Extent2].[Id] WHERE [Extent1].[OrgId] IN ( cast ( '4e108b91-be3c-4cf4-a074-3767b9b8c7dc' as uniqueidentifier), cast ( '1cc15f8c-3758-47d3-862a-5287ab5d0651' as uniqueidentifier), cast ( 'e1bf6f5a-800a-4fd4-9309-576c1d84ba2f' as uniqueidentifier), cast ( 'a436b8a9-4b3a-4bf9-bbdd-839571e03915' as uniqueidentifier), cast ( 'b0d6aead-e72f-4fd5-b2cd-e575454d3a4c' as uniqueidentifier) ) |
条件关联查询,并实现分页
var list = dal.FindByPage(start, pageSize, u => u.OrderByDescending(c => c.CreateTime), u => u.UserOrgIds.All(o => ids.Contains(o.OrgId)), out total); //防止转json时候嵌套异常 var result = from f in list select new { Id = f.Id, UserName = f.UserName, Address = f.Address, Email = f.Email, Sex = f.Sex, CreateUser = f.CreateUser, CreateTime = f.CreateTime, NickName = f.NickName, Phone = f.Phone, QQ = f.QQ, Remark = f.Remark, UserPwd = f.UserPwd }; return result;
public virtual IEnumerable<T> FindByPage(int startIndex, int pageSize, Func<IQueryable<T>, IOrderedQueryable<T>> order, Expression<Func<T, bool>> filters, out int Total) { try { IQueryable<T> rs = order(DBSET.Where(filters)); Total = rs.Count(); if (startIndex < 0 || pageSize < 1) { return null;// rs.ToList(); } else { return rs.Skip(startIndex * pageSize).Take(pageSize).ToList(); } } catch (Exception e) { Total = 0; log.Error("FindByPage:" + order.ToString() + " " + filters.ToString() + " " + e.Message); return null; } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架