-- .net core 与 EF Core 3.1的一些简介和常用用法
【官网】:https://docs.microsoft.com/zh-cn/ef/core/
应用场景
1. LINQ提供了一致的查询语言,提高了代码的可读性。 2. LINQ提供了常用算法,减轻了编码负担,提高了代码的可维护性。 3. Code First简洁的修饰,不喜欢繁琐的XML配置的人士会喜欢 基础资源
.net core
使用须知
1)相比EF,Linq to Sql是个功能十分有限的ORM。 2)与NHibernate的区别在于:NHibernate利用反射Reflection与元数据Metadata实现了ORM,并提供了类似SQL的HQL查询语言(Hibernate Query Language)以及条件对象(Criteria Object),极大地解放了数据库访问的实现,使PI设计(Persistence Ignore,持久化无关)变得越发容易 .3
配置步骤
【关于EF与Linq】
1. LINQ ≠ LINQ to SQL,LINQ ≠ LINQ to Entity,不要一提到LINQ,就把它与数据库挂上钩。
2. 除了LINQ to SQL、LINQ to Entity以外,LINQ to Objects、LINQ to Xml、LINQ to DataSet也是LINQ的重要组成。其中的LINQ to DataSet,更是Access与Excel相关应用的利器。
3. 包括NHibernate、iBatis在内,为了满足PI需要,所有的ORM工具都会有效率上的损失。
4. 原生的SQL语句尽管强大,但无法避免不同数据库之间的兼容性问题,以及提供优雅简洁的代码。
【实际应用一些体会】
以LINQ to Entity为代表的Entity Framework开始走上前台,成为.NET平台下新兴的ORM工具。借由Code First对POCO(Plain Old CLR Object)声明式的特性修饰、简洁的Fluent API和复杂的Object Services,EF为Unit of Worker、Identity Map、Data Mapper等PoEAA模式的简洁实现提供了强大支持。EF Migration则在不变更领域模型设计的前提下,可以变更数据库设计而不破坏原有数据,或进行数据的迁移,尽管我还不是非常熟悉它。通过各种定制的Provider,我们还将SQL的兼容性问题,部分地推给了数据库厂商。
在EF下使用Code First的方式,避免了NHibernate繁琐的配置过程,转而改用一些直观的特性修饰和内嵌的数据库构造器,确保了代码的简洁易读和对数据库更全面的控制。如果说二者同作为ORM工具,有一定程度的对应关系,那么可以把EF 里的DbContext对应于NHibernate里的ISession,但是后者通过HQL与查询对象实现的查询,就没有EF中的LINQ表达式来得简洁和优雅了。
在学习和实践EF Code First的过程中,我完成了一个小项目的升级。通过装配不同的数据访问程序集,达到修改POCO与表之间映射关系的目的,成功实现了数据库中表的垂直分割与水平分割,而未影响其他层的实现。但是,期间也暴露出一些问题:
1. POCO类要承载许多类似[Key]、[Table]之类的声明修饰,使POCO对象变得臃肿,并且变相地与数据库建立了耦合。
2. 复杂的映射逻辑仍需要通过重载OnModelCreating()实现,又再添POCO类与底层间的耦合。
3. LINQ to Entity仍存在一些问题,Include()方法时常会遇到类型失配的运行错误。
【选择Linq与Entity framework的理由】
1. LINQ提供了一致的查询语言,提高了代码的可读性。
2. LINQ提供了常用算法,减轻了编码负担,提高了代码的可维护性。
3. 我喜欢Code First简洁的修饰,不喜欢繁琐的XML配置
常见问题
-
linq to sql有时速度很慢(已经建立了相关索引)
【解决方案】可以排查是否在linq to sql中使用了: ToString,Convert 之类的表达式,需要移出去得到值放进来
快速入门
【linq to sql类中基本的命名空间】
using System.Linq;
using Microsoft.EntityFrameworkCore;
【基本写法】
var query=from U in _context.UserInfo
join UType in _context.UserTypeInfo On U.TypeId equals UType.TypeId
join UDevice in _context.UserDeviceInfo On new {U.UserId,UType.SceneType} equals new {UDevice.UserId,UDevice.SceneType} //这里On new {} equals new {}是实现类似on后面多组条件的且关系,注意new中对象的键名和顺序要一致。
into UDs from UD in UDs.DefaultIfEmpty() //这里的into 之后再 from .. in 实现类似left join的效果
where U.UserName={UserName}
select new ApiResponseResult{
}; //如果返回是某个表,则直接用 select U;这种形式。
【id in()这种写法】
from uc in ucList.DefaultIfEmpty()
where new int[] { 1, 2, 3, 4, 6, 7, 10 }.Contains(u.Id)
select uc;
【like写法】
var list = dbContext.Users.Where(u => u.Name.StartsWith("小") && u.Name.EndsWith("新"))
.OrderBy(u => u.Id)
.Skip(3).Take(5);
【group 写法】
var query = from p in context.Set<Post>()
group p by p.AuthorId into g
select new { g.Key, Count = g.Count() };
【分页】
query.ToList().Skip((PageIndex - 1) * PageSize).Take(PageSize); //错误示例:假分页
query.Skip((PageIndex - 1) * PageSize).Take(PageSize).ToList(); //正确示例: 真分页
【性能优化】
1)非跟踪查询(适用于无需修改,仅查询的场景).
var blogs = context.Blogs .AsNoTracking() .ToList();
[注]使用ToList()的时候会立马执行数据库sql查询.
其它的还有:Count() 、FirstOrDefault()、迭代器IEnumerable/foreach 等都会立刻执行sql。
封装函数的时候可以返回IQueryable<T>,而不是IEnumable<T>,防止立马查询数据库