zoukankan      html  css  js  c++  java
  • 幸福框架:准备抽象NHibernate和EntityFramework,大家给点意见

    背景

    考虑到目前中小企业应用的主流是ORM,我准备在NHibernate和EntityFramework之间找到一个抽象层,也就是说我准备只支持NHibernate和EntityFramework。

    思路

    NH和EF都实现了“工作单元”和“主键映射”这两种企业应用模式,而这两种模式其实就是管理一种状态机,如下图:

    实现

    工作单元接口

      1 using System;
      2 using System.Collections.Generic;
      3 using System.Linq;
      4 using System.Text;
      5 using System.Threading.Tasks;
      6 
      7 namespace Happy.Domain
      8 {
      9     /// <summary>
     10     /// 工作单元接口。
     11     /// </summary>
     12     /// <remarks>
     13     /// 聚合状态:
     14     /// <list type="number">
     15     ///     <item>transient:实例存在于内存中,但不存在于工作单元和数据库中。</item>
     16     ///     <item>persistent in database:实例存在于数据库中。</item>
     17     ///     <item>persistent in unitofwork:实例存在于工作单元中。</item>
     18     ///     <item>detached:实例存在于内存和数据库中,但不存在于工作单元中。</item>
     19     /// </list>
     20     /// 合法转换:
     21     /// <list type="number">
     22     ///     <item>transient > Save -> persistent in unitofwork,Flush时会生成Insert Sql,场景:从UI层创建实例,执行创建。</item>
     23     ///     <item>detached -> Update -> persistent in unitofwork,Flush时会生成Update Sql,场景:从UI层重建实例,执行修改(支持离线乐观并发)。</item>
     24     ///     <item>detached -> Persist -> persistent in unitofwork,Flush时不会生成Sql,场景:将实例从另一个工作单元脱钩,添加到当前工作单元。</item>
     25     ///     <item>detached -> Delete -> persistent in unitofwork,Flush时会生成Delete Sql,场景:从UI层重建实例,删除记录。</item>
     26     ///     <item>detached -> Merge -> persistent in unitofwork,Flush时会生成Update Sql,场景:从UI层重建实例,合并到从数据库重建的实例,执行修改(不支持离线乐观并发)。</item>
     27     ///     <item>persistent in unitofwork -> Evict -> detached,Flush时不会生成Sql,场景:将实例从当前工作单元脱钩,添加到另一个工作单元。</item>
     28     ///     <item>persistent in unitofwork -> Delete -> persistent in unitofwork,Flush时会生成Delete Sql,场景:从数据库重建实例,删除记录。</item>
     29     ///     <item>persistent in unitofwork -> Flush -> persistent in database,提交工作单元,会生成SQL,场景:执行完一系列Create、Update和Delete后统一提交,只产生一次数据库往返。</item>
     30     ///     <item>persistent in database -> Load -> persistent in unitofwork,从数据库重建实例。</item>
     31     ///     <item>persistent in database -> Refresh -> persistent in unitofwork,从数据库刷新实例,场景:使用存储过程修改了一个实例,使用此方法重新刷新一下。</item>
     32     /// </list>
     33     /// </remarks>
     34     public interface IUnitOfWork : IDisposable
     35     {
     36         /// <summary>
     37         /// 判断<paramref name="item"/>是否 persistent in unitofwork。
     38         /// </summary>
     39         bool Contains<TAggregateRoot>(TAggregateRoot item)
     40             where TAggregateRoot : AggregateRoot;
     41 
     42         /// <summary>
     43         /// transient > Save -> persistent in unitofwork,Flush时会生成Insert Sql,场景:从UI层创建实例,执行创建。
     44         /// </summary>
     45         void Save<TAggregateRoot>(TAggregateRoot item)
     46             where TAggregateRoot : AggregateRoot;
     47 
     48         /// <summary>
     49         /// detached -> Update -> persistent in unitofwork,Flush时会生成Update Sql,场景:从UI层重建实例,执行修改(支持离线乐观并发)。
     50         /// </summary>
     51         void Update<TAggregateRoot>(TAggregateRoot item)
     52             where TAggregateRoot : AggregateRoot;
     53 
     54         /// <summary>
     55         /// detached -> Persist -> persistent in unitofwork,Flush时不会生成Sql,场景:将实例从另一个工作单元脱钩,添加到当前工作单元。
     56         /// </summary>
     57         void Persist<TAggregateRoot>(TAggregateRoot item)
     58             where TAggregateRoot : AggregateRoot;
     59 
     60         /// <summary>
     61         /// 执行如下两种转换:
     62         /// <list type="number">
     63         ///     <item>detached -> Delete -> persistent in unitofwork,Flush时会生成Delete Sql,场景:从UI层重建实例,删除记录。</item>
     64         ///     <item>persistent in unitofwork -> Delete -> persistent in unitofwork,Flush时会生成Delete Sql,场景:从数据库重建实例,删除记录。</item>
     65         /// </list>
     66         /// </summary>
     67         void Delete<TAggregateRoot>(TAggregateRoot item)
     68             where TAggregateRoot : AggregateRoot;
     69 
     70         /// <summary>
     71         /// detached -> Merge -> persistent in unitofwork,Flush时会生成Update Sql,场景:从UI层重建实例,合并到从数据库重建的实例,执行修改(不支持离线乐观并发)。
     72         /// </summary>
     73         void Merge<TAggregateRoot>(TAggregateRoot item)
     74             where TAggregateRoot : AggregateRoot;
     75 
     76         /// <summary>
     77         /// persistent in unitofwork -> Evict -> detached,Flush时不会生成Sql,场景:将实例从当前工作单元脱钩,添加到另一个工作单元。
     78         /// </summary>
     79         void Evict<TAggregateRoot>(TAggregateRoot item)
     80             where TAggregateRoot : AggregateRoot;
     81 
     82         /// <summary>
     83         /// persistent in unitofwork -> Flush -> persistent in database,提交工作单元,会生成SQL,场景:执行完一系列Create、Update和Delete后统一提交,只产生一次数据库往返。
     84         /// </summary>
     85         void Flush();
     86 
     87         /// <summary>
     88         /// persistent in database -> Load -> persistent in unitofwork,从数据库重建实例。
     89         /// </summary>
     90         TAggregateRoot Load<TAggregateRoot>(Guid id)
     91             where TAggregateRoot : AggregateRoot;
     92 
     93         /// <summary>
     94         /// persistent in database -> Refresh -> persistent in unitofwork,从数据库刷新实例,场景:使用存储过程修改了一个实例,使用此方法重新刷新一下。
     95         /// </summary>
     96         void Refresh<TAggregateRoot>(TAggregateRoot item)
     97             where TAggregateRoot : AggregateRoot;
     98 
     99         /// <summary>
    100         /// 回滚所有自上次提交以后的修改。
    101         /// </summary>
    102         void Clear();
    103 
    104         /// <summary>
    105         /// 清空处于persistent in unitofwork状态的实例。
    106         /// </summary>
    107         TRepository GetRepository<TRepository>()
    108             where TRepository : IRepository;
    109     }
    110 }

    基于EntityFramework的工作单元

      1 using System;
      2 using System.Collections.Generic;
      3 using System.Linq;
      4 using System.Text;
      5 using System.Threading.Tasks;
      6 using System.Data;
      7 using System.Data.Entity;
      8 using System.Data.Entity.Infrastructure;
      9 
     10 using Microsoft.Practices.ServiceLocation;
     11 
     12 using Happy.Domain;
     13 using Happy.DesignByContract;
     14 
     15 namespace Happy.EntityFramework
     16 {
     17     /// <summary>
     18     /// 基于EntityFramework的工作单元。
     19     /// </summary>
     20     public abstract class UnitOfWork : DbContext, IUnitOfWork
     21     {
     22         private readonly Dictionary<Type, IRepository> repositories = new Dictionary<Type, IRepository>();
     23 
     24         /// <summary>
     25         /// 构造方法。
     26         /// </summary>
     27         protected UnitOfWork()
     28         {
     29         }
     30 
     31         /// <summary>
     32         /// 构造方法。
     33         /// </summary>
     34         protected UnitOfWork(string nameOrConnectionString)
     35             : base(nameOrConnectionString)
     36         {
     37         }
     38 
     39         /// <inheritdoc />
     40         public bool Contains<TAggregateRoot>(TAggregateRoot item)
     41             where TAggregateRoot : AggregateRoot
     42         {
     43             item.MustNotNull("item");
     44 
     45             return this.Entry(item).State != EntityState.Detached;
     46         }
     47 
     48         /// <inheritdoc />
     49         public void Save<TAggregateRoot>(TAggregateRoot item)
     50             where TAggregateRoot : AggregateRoot
     51         {
     52             item.MustNotNull("item");
     53 
     54             this.Set<TAggregateRoot>().Add(item);
     55         }
     56 
     57         /// <inheritdoc />
     58         public void Update<TAggregateRoot>(TAggregateRoot item)
     59             where TAggregateRoot : AggregateRoot
     60         {
     61             item.MustNotNull("item");
     62 
     63             this.Entry(item).State = EntityState.Modified;
     64         }
     65 
     66         /// <inheritdoc />
     67         public void Persist<TAggregateRoot>(TAggregateRoot item)
     68             where TAggregateRoot : AggregateRoot
     69         {
     70             item.MustNotNull("item");
     71 
     72             this.Entry(item).State = EntityState.Unchanged;
     73         }
     74 
     75         /// <inheritdoc />
     76         public void Delete<TAggregateRoot>(TAggregateRoot item)
     77             where TAggregateRoot : AggregateRoot
     78         {
     79             item.MustNotNull("item");
     80 
     81             this.Entry(item).State = EntityState.Deleted;
     82         }
     83 
     84         /// <inheritdoc />
     85         public void Merge<TAggregateRoot>(TAggregateRoot item)
     86             where TAggregateRoot : AggregateRoot
     87         {
     88             item.MustNotNull("item");
     89 
     90             var persistItem = this.Set<TAggregateRoot>().Find(item.Id);
     91 
     92             this.Entry(persistItem).CurrentValues.SetValues(item);
     93         }
     94 
     95         /// <inheritdoc />
     96         public void Evict<TAggregateRoot>(TAggregateRoot item)
     97             where TAggregateRoot : AggregateRoot
     98         {
     99             item.MustNotNull("item");
    100 
    101             this.Entry(item).State = EntityState.Detached;
    102         }
    103 
    104         /// <inheritdoc />
    105         public void Flush()
    106         {
    107             try
    108             {
    109                 base.SaveChanges();
    110             }
    111             catch (DbUpdateConcurrencyException ex)
    112             {
    113                 throw new OptimisticConcurrencyException(ex.Message, ex);
    114             }
    115         }
    116 
    117         public TAggregateRoot Load<TAggregateRoot>(Guid id)
    118             where TAggregateRoot : AggregateRoot
    119         {
    120             return this.Set<TAggregateRoot>().Find(id);
    121         }
    122 
    123         public void Refresh<TAggregateRoot>(TAggregateRoot item)
    124             where TAggregateRoot : AggregateRoot
    125         {
    126             item.MustNotNull("item");
    127 
    128             this.Entry(item).Reload();
    129         }
    130 
    131         /// <inheritdoc />
    132         public void Clear()
    133         {
    134             base.ChangeTracker.Entries()
    135                               .ToList()
    136                               .ForEach(entry => entry.State = System.Data.EntityState.Detached);
    137         }
    138 
    139         /// <inheritdoc />
    140         public TRepository GetRepository<TRepository>()
    141             where TRepository : IRepository
    142         {
    143             var key = typeof(TRepository);
    144 
    145             if (!repositories.ContainsKey(key))
    146             {
    147                 var repository = ServiceLocator.Current.GetInstance<TRepository>();
    148                 (repository as IEntityFrameworkRepository).Owner = this;
    149                 repositories[key] = repository;
    150             }
    151 
    152             return (TRepository)repositories[key];
    153         }
    154     }
    155 }

    备注

    其实我们经常忽略一个关于接口的问题,就是异常本身也是API的一部分,虽然这部分在C#中没有办法显式的表达,等我的朋友实现完了NH版本的工作单元的开发,我们就继续对异常进行抽象。

  • 相关阅读:
    使用a标签制作tooltips
    使用editorconfig配置你的编辑器
    JointJS绘制流程图
    用highcharts展现你的数据
    css段落首字母下沉
    sklearn框架的系统学习
    numpy删除二维数据矩阵的行和列
    sklearn中机器学习算法评价指标
    sklearn调用逻辑回归算法
    sklearn调用多项式回归
  • 原文地址:https://www.cnblogs.com/happyframework/p/3109697.html
Copyright © 2011-2022 走看看