One of the mistakes I see people make (and have made myself) is assuming that you must choose exactly one ORM strategy for an entire database/application/system. It’s simply not the case. You can (and should) tailor your ORM strategy to your use case, and make sure you’re picking the right tool (or feature of the tool) for the job.

First things first – 99.9% of the time, you should never use ADO.NET classes directly, including IDbCommand and IDataReader. If you’re still doing “dataReader.MoveNext” – you are writing code that you should not write, ever again. There are better options for what you’re trying to do.

Now, there are lots of folks who don’t like ORMs, and from listening on how those folks chose their ORM strategies, I would agree. Fowler said on OrmHate that:

much of the frustration with ORMs is about inflated expectations

We have to move past the idea that ORMs are bad or ugly or bloatware. ORMs are meant to solve a problem, with many different options for doing so. But before we look at options, let’s look at the problem space. What is the problem we’re trying to solve?

Bridging the gap

If you have to push/pull data to/from SQL and .NET, you have to map your .NET data types to SQL. In .NET, this means using ADO.NET to communicate SQL commands to a SQL database. At some point, mapping has to happen between SQL data types and .NET data types. SQL dates are different than .NET dates, and so on.

ADO.NET helps with this, but leaves the work up to you for taking raw result sets and populating objects. And ultimately, that’s what we want to do – work with objects and types in .NET, and let something flow our objects/data back and forth to SQL.

ORMs are meant to help solve this problem, by applying layers on top of ADO.NET of various abstractions and weight. But there are many different strategies for doing so, used to solve this problem in many different ways.

Let’s look at each of these in turn and see where they might fit.

Entity-based relational mapping

In entity-based relational mapping, tables are more or less 1:1 with entities in your object design. When you add a property to an object, a column is added to the database. Usage of entity-based relational mapping centers around loading up an entity (or aggregate) by its identifier, manipulating that object and perhaps child objects, and saving that object back through the ORM.

The ORM in this case provides many features, like:

If I’m working with effectively one entity or aggregate at a time, tools like NHibernate use mapping configuration to keep track of entities loaded and automatically flush changes upon committing the transaction. This is nice because we don’t have to transport a data access gateway around, it’s just managed for us.

When loading up an item by Id for manipulation purposes, this option works great. It removes quite a bit of code I would otherwise need to write to keep track of adding objects, saving them and so on. I would have to “remember” to save things and the like.

The downside is that the ORM does not immediately know that you’re just reading objects, or loading up an entity to manipulate it. We often see folks stumble when not understanding that change tracking is turned on by default, and when you load up entities, the assumption is that we need to check to see if it’s changed.

If you’re looking at loading up an entity in order to manipulate it and persist changes (or create a new entity to manipulate), this pattern allows a greater deal of freedom of keeping data access concerns into infrastructure layers, and let your entity types be relatively persistent-ignorant. Persistence ignorance is not that my C# model and DB model can diverge, but more that data access concerns don’t leak into my object model, which I’d rather be more concerned with business rules.

Active Record is another flavor of entity-based usage, except data access concerns are embedded with my object model.

Result-set-based relational mapping

In most applications, the demands for reads greatly outstrips the instances of writes. We’ve seen ratios of 100:1 looking at the profiler of SELECTs to INSERT/UPDATE/DELETEs in one recent application. When looking at what SQL is very good at, it’s great at working with data in sets. To return sets back to the application, it often makes zero sense to try and use an entity-based approach for simply returning sets of data.

But we still would like to not work with very raw SQL objects like IDataReader or DataTables. These are very loosely-typed objects, not easily transferable to upper layers of the application.

Instead, we often build objects who are tailor-made for data. These are often called Data-Transfer Objects, or Read Models. These are types we craft for individual SQL SELECT queries, not to be re-used across other queries.

Many ORMs have features optimized for these scenarios. In NHibernate, you can use projections to skip any sort of tracked Entity objects to map straight to DTOs, you can use SQL queries to map straight to DTOs and skip needing to configure mapping. Or you can use micro-ORMs like PetaPoco.

These reads can also stream objects as they are read. Both NHibernate and several micro-ORMs let you map individual DTO instances as each row is read from the underlying result set, minimizing the amount of objects kept around in memory.

In our applications, we often still use NHibernate for reads, but skip any kind of entity objects and instead craft our raw SQL, relying on NHibernate’s optimized mappers to simply supply a DTO type and the results are mapped automatically.

This approach does not work well if we have to apply business rules and persist information back, as these models usually map to result sets, not database tables.

DML-based relational mapping

If you know what you want to do in SQL for CRUD operations, and would rather not have a tool figure it out for you, you’re really looking for something to effectively abstract DML commands at a step higher than ADO.NET.

This is the arena of micro ORMs. Tools like PetaPocoDapperMassive and others work to solve the problem of the pain of working with raw ADO.NET. These typically still allow us to work with objects, but our interactions are greatly simplified and SQL is brought to the forefront. We only need a connection, and these tools can let us work with all the CRUD operations in a manner that offers much simpler code that ADO.NET

In cases where you don’t already have an entity-based relational mapper in the application, micro-ORMs provide a much lighter approach. Because types and mappings are not configured ahead of time, these tools rely on lazily-evaluated optimized reflection caching techniques to on-the-fly map parameters and result sets.

Many applications can start out with DML-based mappings, graduating to a full-fledged ORM when certain relationships or entities demand it.

Bulk loading tools

One that holds a dear place in my heart – sometimes you don’t want to push/pull data in an object-based manner. Instead, you’d rather push and pull data in bulk. Tools like SQL Bulk Copy allow you to pull data out in a delimited or tabular format, or push data in.

Bulk loading tools typically work as a sort of bazooka, blasting data out or blasting data in, but not providing much beyond that. You won’t be able to do updates or deletes, but for getting large amounts of data in and out of SQL, bulk loading tools are what you need.

In many integration scenarios where you provide delimited files to partners, or delimited files are supplied to you, bulk loaders allow you to treat files as tables and load them directly against the database, skipping past layers of abstractions both in mapping objects and even in the database.

These tools are tuned to be much, much quicker than traditional methods of extracting/loading data. In some of our tests, we’ve seen orders of magnitude differences of time between row-by-row loading versus bulk load. In one case, we saw a difference between several hours and less than a minute to load.

The downside is that options are quite limited, and you’re really only limited to INSERT and SELECT. Everything else requires different tools.

Right tool for the job

In one recent project, I’ve used every single one of these approaches against a single database and a single codebase. NHibernate for entity/aggregate-based mapping, result-set for reading sets of data (and building messages/exports/views from the results), DML-based mappings for simple tables and modules, and bulk loading tools for those nightly drops of million-row files from partners.

The key is to not tie yourself down to a specific tool or approach. No single ORM strategy works for every situation, and nor should it. NHibernate can work for a variety of scenarios beyond entity-based mappings, but doesn’t do everything. Complexity often arises from trying to use the same approach for every situation.

Every application written outside of SQL uses an ORM. Whether it’s hand-rolled ADO.NET code, or NHibernate, you have to bridge the gap from .NET to SQL. Bridging this gap is a hard problem to solve, and nothing solves the entire problem set perfectly. Nor should it!

Choose the approach that fits the problem at hand, and don’t worry about having multiple approaches in a single solution. That’s not to say haphazard decisions are appropriate, but informed, educated decisions based on knowledge of all choices at hand are always a good idea.

from: http://lostechies.com/jimmybogard/2012/07/20/choosing-an-orm-strategy/

Choosing an ORM strategy的更多相关文章

  1. Inheritance with EF Code First: Part 3 – Table per Concrete Type (TPC)

    Inheritance with EF Code First: Part 3 – Table per Concrete Type (TPC) This is the third (and last) ...

  2. selenium-网站demo学习-test Design-优化自动化代码

    看selenium的网站的文档,里面的自动化用例设计有一些小点很靠谱.学了很多,可以用作优化自己的代码. 1.测试类型: Testing Static Content Testing Links Fu ...

  3. Character Encoding in .NET

    https://docs.microsoft.com/en-us/dotnet/standard/base-types/character-encoding#Encodings Characters ...

  4. 6. Design Patterns with First-Class Functions

    1. Refactoring Strategy 1.1 Classic Strategy from abc import ABC, abstractmethod from collections im ...

  5. selenium docs

    Note to the Reader - Docs Being Revised for Selenium 2.0! Introduction Test Automation for Web Appli ...

  6. .NET ORM框架(一)

    最近做项目自己整理了一个ORM框架,分享给大家看看,有很多不足望大家指出. 下面是使用方法 BLL 主要方法 逻辑层:子类继承父类, 直接用BASE调用 ManagerBLL 中的方法. public ...

  7. Hibernate第一篇【介绍Hibernate,简述ORM,快速入门】

    前言 前面已经学过了Struts2框架了,紧接着就是学习Hibernate框架了-本博文主要讲解介绍Hibernate框架,ORM的概念和Hibernate入门 什么是Hibernate框架? Hib ...

  8. springboot~JPA把ORM统一起来

    JPA介绍 JPA(Java Persistence API)是Sun官方提出的Java持久化规范.它为Java开发人员提供了一种对象/关联映射工具来管理Java应用中的关系数据.他的出现主要是为了简 ...

  9. 【ORM框架】Spring Data JPA(一)-- 入门

    本文参考:spring Data JPA入门   [原创]纯干货,Spring-data-jpa详解,全方位介绍  Spring Data JPA系列教程--入门 一.Spring Data JPA介 ...

随机推荐

  1. Java开发必用的工具包

    Java是最流行的开源语言之一. 有赖于Java的开源,涌现出一大批优秀的开源框架,基本涵盖了开发中的方方面面,让程序员可以专注于自己的业务逻辑. ​ 今天,我们就来聊聊在开发中,经常被我们所忽略的[ ...

  2. POJ 2752 Seek the Name, Seek the Fame(KMP求公共前后缀)

    题目链接:http://poj.org/problem?id=2752 题目大意:给你一串字符串s找到所有的公共前后缀,即既是前缀又是后缀的子串. 解题思路: 如图所示 假设字符串pi与jq为符合条件 ...

  3. python discover 函数介绍

    discover(start_dir,pattern='test*.py',top_level_dir=None)找到指定目录下所有测试模块,并可递归查到子目录下的测试木块,只有匹配到的文件名才会被加 ...

  4. 使用Opencv时编译错误

    1)无法打开包括文件: “cv.h”: No such file or directory 我的配置文件没有问题,但是一直报错,我是在HEVC测试软件HM中调用了opencv. HM有很多个工程,我只 ...

  5. fedora安装后的配置

    fedora安装后的一些配置 (mirror)源 换源 默认从fedora官网下载太慢,考虑换用国内的源(镜像站点),推荐中科大.阿里云.浙大.网易等的源. 比如我用浙大ZJU的源http://mir ...

  6. import xxx from 和 import {xxx} from的区别

    1.vue import FunName from ‘../xxx’ 1.js export defualt function FunName() { return fetch({ url: '/ar ...

  7. 简易解析ajax,javascript-XMLHttpRequest

    XMLHttpRequest可以提供不重新加载页面的情况下更新网页 <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/ ...

  8. elementUI 学习入门之 input 输入框

    基础用法 <el-input v-model="input1" palcehoder="请输入"></el-input> var Mai ...

  9. SPOJ GSS3-Can you answer these queries III-分治+线段树区间合并

    Can you answer these queries III SPOJ - GSS3 这道题和洛谷的小白逛公园一样的题目. 传送门: 洛谷 P4513 小白逛公园-区间最大子段和-分治+线段树区间 ...

  10. JAVA编程思想读书笔记(五)--多线程

    接上篇JAVA编程思想读书笔记(四)--对象的克隆 No1: daemon Thread(守护线程) 参考http://blog.csdn.net/pony_maggie/article/detail ...