本文共 3521 字,大约阅读时间需要 11 分钟。
最近工作中遇到数据库组合查询带来的一些问题,因此有必要调研一下Linq to Objects Join Linq to Entity。参考一些网友的代码案例,深入实践了一下使用EntityFramework Code First 下的组合查询。
准备环节:
(一) 在VS下创建一个控制台应用程序(LinqToObjectJoinEntity),定义一个MyObject类,如下:
public class MyObject
{ public int Identity { get; set; } public string Name { get; set; } public int Age { get; set; } }(二)然后再定义一个Entity类及EntityContext类。
public class Entity
{ public int EntityId { get; set; } public string Name { get; set; } public string Notes { get; set; } }public class EntityContext : DbContext
{ public IDbSet<Entity> Entitys { get; set; }protected override void OnModelCreating(DbModelBuilder modelBuilder)
{ modelBuilder.Conventions.Remove<System.Data.Entity.ModelConfiguration.Conventions.PluralizingTableNameConvention>(); // 此处是避免使用EF创建出来的Entity表为复数形式,顺便吐槽下微软默认给复数的设计 modelBuilder.Conventions.Remove<System.Data.Entity.ModelConfiguration.Conventions.OneToManyCascadeDeleteConvention>(); // 此处是避免使用EF创建出的数据库包含数据迁移表base.OnModelCreating(modelBuilder);
} }(三)使用EF创建准备数据(在Main()函数中实现):
using (var db = new EntityContext())
{ db.Entitys.Add(new Entity { EntityId = 1, Name = "Entity", Notes = "Notes" }); db.Entitys.Add(new Entity { EntityId = 2, Name = "Frame", Notes = "Mates" }); db.Entitys.Add(new Entity { EntityId = 3, Name = "Work", Notes = "Honor" });db.SaveChanges();
}
Coding实践:
(1)重现Linq to Object Join Linq to Entity
#region Reproduce Linq to Object Join Linq to Entity
var objectNames = (from myObject in myObjects
join entity in db.Entitys on myObject.Identity equals entity.EntityId select myObject.Name).ToList();#endregion
使用Sql Profiler观察到的查询语句如下:
SELECT
[Extent1].[EntityId] AS [EntityId], [Extent1].[Name] AS [Name], [Extent1].[Notes] AS [Notes] FROM [dbo].[Entity] AS [Extent1]属于全表查询,此乃Linq to objects Join Linq to Entity一大弊害。
(2)重现 Linq to Entity Join Linq to Object
#region Reproduce Linq to Entity Join Linq to Object
var entityName = (from entity in db.Entitys
join myObject in myObjects on entity.EntityId equals myObject.Identity select entity.Name).ToList();#endregion
这个地方运行时会抛异常:
Only Primitive types ('Such as Int32, string, and Guid') are supported in this context
中文意思是“无法创建类型为“项目名.MyObject”的常量值。此上下文仅支持基元类型(“例如 Int32、String 和 Guid”)"
看来在涉及这种操作时,我们内存中的数据还不能是非基元类型。List<MyObject> objectList = new List<MyObject>();
MyObject要为int32, string或者Guid,才能运行通过,并且不是整表查询,而是针对name列的单独查询。
(3)改进 Linq to Entity Join Linq to Object
#region Linq to Entity Join Linq to Object(Resolve)
var identities = myObjects.Select(o => o.Identity);
var entitytNames = (from entity in db.Entitys
join identity in identities on entity.EntityId equals identity select entity.Name).ToList();#endregion
这里Sql Profile监测到的查询语句为:
SELECT
[Extent1].[Name] AS [Name] FROM [dbo].[Entity] AS [Extent1] INNER JOIN (SELECT 1 AS [C1] FROM ( SELECT 1 AS X ) AS [SingleRowTable1] UNION ALL SELECT 2 AS [C1] FROM ( SELECT 1 AS X ) AS [SingleRowTable2] UNION ALL SELECT 3 AS [C1] FROM ( SELECT 1 AS X ) AS [SingleRowTable3]) AS [UnionAll2] ON [Extent1].[EntityId] = [UnionAll2].[C1]虽是麻烦了些,查出来的东西只有一个。
此文只是针对性的简述下Linq to Object Join Linq to Entity的场景,在日常工作中可能不止于此。
代码见:
墨匠
转载地址:http://slqpo.baihongyu.com/