在 .NET Core 中选择正确的对象关系映射 (ORM) 工具可能是开发生命周期中的关键决策。所选的 ORM 会影响应用程序的性能、可维护性和可伸缩性。在本文中,我们将深入分析三个突出的 ORM 选择:Entity Framework Core、Dapper 和 NHibernate。
每个 ORM 都有其优点和缺点,我们将通过实际的代码示例来探索它们。1. 实体框架核心实体框架核心(EF Core)是Microsoft的官方ORM,以其简单性和与其他Microsoft技术的集成而闻名。它支持各种数据库提供程序,并遵循约定优先于配置的方法。让我们深入研究一个详细的例子:模型定义public
在 .NET Core 中选择正确的对象关系映射 (ORM) 工具可能是开发生命周期中的关键决策。所选的 ORM 会影响应用程序的性能、可维护性和可伸缩性。在本文中,我们将深入分析三个突出的 ORM 选择:Entity Framework Core、Dapper 和 NHibernate。每个 ORM 都有其优点和缺点,我们将通过实际的代码示例来探索它们。
1. EF Core
Entity Framework (EF) Core 是轻量化、可扩展、开源和跨平台版的常用 Entity Framework 数据访问技术。
EF Core 可用作对象关系映射程序 (O/RM),这可以实现以下两点:
- 使 .NET 开发人员能够使用 .NET 对象处理数据库。
- 无需再像通常那样编写大部分数据访问代码。
- EF查询使用的是LINQ进行查询
让我们深入研究一个详细的例子:
模型定义
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public int Rating { get; set; }
public List<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
public Blog Blog { get; set; }
}
数据库上下文
public class BloggingContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(
@"Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True");
}
}
查询数据
using (var db = new BloggingContext())
{
var blogs = db.Blogs
.Where(b => b.Rating > 3)
.OrderBy(b => b.Url)
.ToList();
}
保存数据
using (var db = new BloggingContext())
{
var blog = new Blog { Url = "http://sample.com" };
db.Blogs.Add(blog);
db.SaveChanges();
}
EF O/RM 注意事项
虽然 EF Core 善长提取许多编程详细信息,但还是有一些适用于任何 O/RM 的最佳做法,可帮助避免生产应用中的常见陷阱:
- 若要在高性能生产应用中构建、调试、分析和迁移数据,必须具备基础数据库服务器的中级知识或更高级别的知识。 例如,有关主键和外键、约束、索引、标准化、DML 和 DDL 语句、数据类型、分析等方面的知识。
- 功能和集成测试:请务必尽可能严密地复制生产环境,以便:
- 查找仅在使用特定版本的数据库服务器时应用才出现的问题。
- 在升级 EF Core 和其他依赖项时捕获中断性变更。 例如,添加或升级 ASP.NET Core、OData 或 AutoMapper 等框架。 这些依赖项可能以多种意外方式影响 EF Core。
- 通过代表性负载进行性能和压力测试。 某些功能的不成熟用法缩放性不佳。 例如,多项集合包含内容、大量使用延迟加载、对未编制索引的列执行条件查询、对存储生成的值进行大规模更新和插入、缺乏并发处理、大型模型、缓存策略不充分。
- 安全评审:例如,连接字符串和其他机密处理、非部署操作的数据库权限、原始 SQL 的输入验证、敏感数据加密。
- 确保日志记录和诊断充足且可用。 例如,适当的日志记录配置、查询标记和 Application Insights。
- 错误恢复。 为常见故障场景(如版本回退、回退服务器、横向扩展和负载平衡、DoS 缓解和数据备份)准备应急计划。
- 应用程序部署和迁移。 规划如何在部署过程中应用迁移;在应用程序启动时执行此操作可能会导致并发问题,并且对于常规操作,这所需的权限比必要权限更高。 在迁移期间,使用暂存来辅助从错误中恢复。 有关详细信息,请参阅应用迁移。
- 生成的迁移的详细检查和测试。 将迁移应用于生产数据前,应对其进行全面测试。 若表中包含生产数据,架构的形状和列类型就不能轻易更改。 例如,在 SQL Server 上,对于映射到字符串和十进制属性的列,
nvarchar(max)
和decimal(18, 2)
极少成为最佳类型,但这些是 EF 使用的默认值,因为 EF 不了解你的具体情况。
2.Dapper
Dapper 主要能够让你练习你的 SQL 技能,按你认为的那样构建查询和命令。它接近于"金属"而非标准的 ORM,免除了解释查询的工作。Dapper 可以通过其 API 为你执行查询以及---假如查询结果的架构与目标类型的属性相匹配---自动实例化对象并向对象填充查询结果。此处还有另一个显著的性能优势: Dapper 能够有效缓存它获悉的映射,从而实现后续查询的极速反序列化。
DapperDesigner 类
public class DapperDesigner
{
public DapperDesigner() {
Products = new List<Product>();
Clients = new List<Client>();
}
public int Id { get; set; }
public string LabelName { get; set; }
public string Founder { get; set; }
public Dapperness Dapperness { get; set; }
public List<Client> Clients { get; set; }
public List<Product> Products { get; set; }
public ContactInfo ContactInfo { get; set; }
}
查询代码类
var designers = sqlConn.Query<DapperDesigner>("select * from DapperDesigners");
Dapper 和关系查询
var sql = @"select * from DapperDesigners D JOIN Products P ON P.DapperDesignerId = D.Id"; var designers= conn.Query<DapperDesigner, Product,DapperDesigner> (sql,(designer, product) => { designer.Products.Add(product); return designer; });
编码难度加大,执行速度变快
Dapper 是精确控制 SQL 查询和高性能数据访问至关重要的场景的绝佳选择。它对于读取密集型应用程序特别有用。
Dapper使用查询用的是原始的SQL。
3. NHibernate
NHibernate是Hibernate的C#版,众所周知Hibernate是Java 里ORM的顶梁柱。与EntityFramework不同的地方是,Hibernate以配置文件为主,通过配置文件规范使用,Object/Relation 映射。而NHibernate这继承了这一点,也是以配置文件优先
映射
需要创建一个项目用的配置文件:App.config.
C# 项目中,除了Web类型的项目,每个项目的主配置文件的名称都是App.config,这是一个固定名称。
文件内容如下:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
</configuration>
在 configuration节点之间添加以下内容:
<configSections>
<section name="hibernate-configuration" type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate"/>
</configSections>
这段代码的含义是,在config文件中添加一个 hibernate-configuration结点,结点的解析由类:NHibernate.Cfg.ConfigurationSectionHandler,所在包是NHibernate。
在App.config文件configuration结点中添加以下代码:
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<property name="dialect">NHibernate.Dialect.MsSql2012Dialect</property>
<property name="connection.connection_string">
Data Source=.;Initial Catalog=Demo;Integrated Security=True
</property>
<property name="hbm2ddl.auto">create-drop</property>
<mapping assembly="dataprovider" />
</session-factory>
</hibernate-configuration>
这是固定格式,其中dialect表示使用的数据库类型,connection.connection_string 表示连接字符串。mapping表示映射关系文件所在项目。
获取ISessionFactory
然后获取一个ISessionFactory:
Configuration cfg = new Configuration();
var sessionFactory = cfg.BuildSessionFactory();
当然,如果直接运行代码的话,会在 BuildSessionFactory这里报错。因为没有为SQL Server安装数据访问驱动:
System.Data.SqlClient
将数据访问驱动安装成功后,运行可以获得sessionFactory。
sessionFactory用来创建一个访问数据库的Session
增删改查
先来个简单的示例类:
public class Cat
{
public virtual string Id { get; set; }
public virtual string Name { get; set; }
public virtual char Sex { get; set; }
public virtual float Weight { get; set; }
}
NHibernate的映射关系文件:Cat.hbm.xml
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="dataprovider" assembly="dataprovider">
<class name="Cat" table="Cat">
<!-- A 32 hex character is our surrogate key. It's automatically
generated by NHibernate with the UUID pattern. -->
<id name="Id">
<column name="CatId" sql-type="char(32)" not-null="true"/>
<generator class="uuid.hex" />
</id>
<!-- A cat has to have a name, but it shouldn't be too long. -->
<property name="Name">
<column name="Name" length="16" not-null="true" />
</property>
<property name="Sex" />
<property name="Weight" />
</class>
</hibernate-mapping>
创建完成后,右键选中文件,修改文件生成操作为嵌套的资源
然后编写实例代码:
Configuration cfg = new Configuration().Configure();
using (var sessionFactory = cfg.BuildSessionFactory())
using (var session = sessionFactory.OpenSession())
{
// 通过session操作
session.Close();
}
新增一个Cat:
var princess = new Cat
{
Name = "Princess",
Sex = 'F',
Weight = 7.4f
};
session.Save(princess);
session.Flush();//推送修改给数据库,不调用的话数据库里将没有数据
查询并修改:
var cats = session.Query<Cat>().ToList();
var cat = cats.First();
cat.Name = "xiao li";
session.Update(cat);
session.Flush();
查询并删除:
var cats = session.Query<Cat>().ToList();
var cat = cats.First();
session.Delete(cat);
session.Flush();
结论
在 .NET Core 中选择 ORM 涉及评估项目的特定需求和权衡。Entity Framework Core 在简单性和基于约定的开发方面表现出色,Dapper 最适合对性能敏感的方案,而 NHibernate 为复杂的应用程序提供了广泛的功能。根据项目的要求做出明智的决策,你将在 .NET Core 应用程序中实现高效且可维护的数据库交互。
注意:
三种ORM映射虽然采取的映射方式不同,但是在数据操作中都有一个共同的特征就是建立上下文数据库对象或者缓存工厂,以此来简化数据操作的。