• .NET Core 中的 ORM 框架对比


            在 .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进行查询

    让我们深入研究一个详细的例子:

    模型定义

    1. public class Blog
    2. {
    3. public int BlogId { get; set; }
    4. public string Url { get; set; }
    5. public int Rating { get; set; }
    6. public List Posts { get; set; }
    7. }
    8. public class Post
    9. {
    10. public int PostId { get; set; }
    11. public string Title { get; set; }
    12. public string Content { get; set; }
    13. public int BlogId { get; set; }
    14. public Blog Blog { get; set; }
    15. }

    数据库上下文

    1. public class BloggingContext : DbContext
    2. {
    3. public DbSet Blogs { get; set; }
    4. public DbSet Posts { get; set; }
    5. protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    6. {
    7. optionsBuilder.UseSqlServer(
    8. @"Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True");
    9. }
    10. }

    查询数据

    1. using (var db = new BloggingContext())
    2. {
    3. var blogs = db.Blogs
    4. .Where(b => b.Rating > 3)
    5. .OrderBy(b => b.Url)
    6. .ToList();
    7. }

    保存数据

    1. using (var db = new BloggingContext())
    2. {
    3. var blog = new Blog { Url = "http://sample.com" };
    4. db.Blogs.Add(blog);
    5. db.SaveChanges();
    6. }

    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 类

    1. public class DapperDesigner
    2. {
    3. public DapperDesigner() {
    4. Products = new List();
    5. Clients = new List();
    6. }
    7. public int Id { get; set; }
    8. public string LabelName { get; set; }
    9. public string Founder { get; set; }
    10. public Dapperness Dapperness { get; set; }
    11. public List Clients { get; set; }
    12. public List Products { get; set; }
    13. public ContactInfo ContactInfo { get; set; }
    14. }

    查询代码类 

    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这继承了这一点,也是以配置文件优先

    映射

    1. 需要创建一个项目用的配置文件:App.config.
    2. C# 项目中,除了Web类型的项目,每个项目的主配置文件的名称都是App.config,这是一个固定名称。
    3. 文件内容如下:
    4. <?xml version="1.0" encoding="utf-8" ?>
    5. <configuration>
    6. </configuration>
    7. configuration节点之间添加以下内容:
    8. <configSections>
    9. <section name="hibernate-configuration" type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate"/>
    10. </configSections>
    11. 这段代码的含义是,在config文件中添加一个 hibernate-configuration结点,结点的解析由类:NHibernate.Cfg.ConfigurationSectionHandler,所在包是NHibernate。
    12. 在App.config文件configuration结点中添加以下代码:
    13. <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
    14. <session-factory>
    15. <property name="dialect">NHibernate.Dialect.MsSql2012Dialect</property>
    16. <property name="connection.connection_string">
    17. Data Source=.;Initial Catalog=Demo;Integrated Security=True
    18. </property>
    19. <property name="hbm2ddl.auto">create-drop</property>
    20. <mapping assembly="dataprovider" />
    21. </session-factory>
    22. </hibernate-configuration>
    23. 这是固定格式,其中dialect表示使用的数据库类型,connection.connection_string 表示连接字符串。mapping表示映射关系文件所在项目。

    获取ISessionFactory

    1. 然后获取一个ISessionFactory:
    2. Configuration cfg = new Configuration();
    3. var sessionFactory = cfg.BuildSessionFactory();
    4. 当然,如果直接运行代码的话,会在 BuildSessionFactory这里报错。因为没有为SQL Server安装数据访问驱动:
    5. System.Data.SqlClient
    6. 将数据访问驱动安装成功后,运行可以获得sessionFactory。
    7. sessionFactory用来创建一个访问数据库的Session

     增删改查

    1. 先来个简单的示例类:
    2. public class Cat
    3. {
    4. public virtual string Id { get; set; }
    5. public virtual string Name { get; set; }
    6. public virtual char Sex { get; set; }
    7. public virtual float Weight { get; set; }
    8. }
    9. NHibernate的映射关系文件:Cat.hbm.xml
    10. <?xml version="1.0" encoding="utf-8" ?>
    11. <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="dataprovider" assembly="dataprovider">
    12. <class name="Cat" table="Cat">
    13. <!-- A 32 hex character is our surrogate key. It's automatically
    14. generated by NHibernate with the UUID pattern. -->