在数据库表创建完成的情况下,使用DB First 进行开发,封装底层会遇到一些小问题,在此记录一下,供以后参考。

主要解决的问题有:

1、EF上下文管理

2、BaseRepository的封装

3、EF中实体序列化的问题

1、EF上下文管理

EF操作数据库的上下文,要达到在用户每一次的请求操作中都只有一个上下文,当用户通过Http请求结束后要释放用户使用的上下文资源,也就

是EF生成中的ObjectContext不能每次使用时候通过new 创建一个新的实例,一次请求只需要创建一次,请求结束ObjectContext资源释放。

这里要用到的就是单例模式和简单工厂了,单例保证只有一个ObjectContext ,每次调用通过工厂方式获取。这里直接贴代码

    public class DbContextFactory
{
private static string efKey = "ef_key"; public static RBACEntities GetContext()
{
RBACEntities db = CallContext.GetData(efKey) as RBACEntities;
if (db == null)
{
db = new RBACEntities();
CallContext.SetData(efKey,db);
}
Debug.WriteLine("EF上下文获取:" + db.GetHashCode() + ",时间:" + DateTime.Now.ToString("hh-mm-ss ffff"));
return db;
} public static void Dispose()
{
var context=GetContext();
Debug.WriteLine("EF上下文释放:" + context.GetHashCode() + ",时间:" + DateTime.Now.ToString("hh-mm-ss ffff"));
context.Dispose();
}
}

然后,在Global.asax中,在请求结束事件中调用释放资源方法。

        protected void Application_EndRequest()
{
Dedeyi.RBAC2.Core.Model.DbContextFactory.Dispose();
}

     Debug.WriteLine是调试时候,追踪一下上下文的获取和释放是否达到目的。打开调试的Output ,检测到一次请求的输出信息

    可以看到,在这次请求处理中使用了两次上下文实例,都是同一个实例(HashCode相同),最后又一次的资源释放。

2、BaseRepository的封装

基仓储的封装。要实现基本的增删查改操作。在这里因为使用的是Entity Framework 中的ObjectContext进行数据库交互,其灵活性是很强的

如果只是像ADO.NET中通过sql对CRUD的封装那样,就很多地方没法发挥ObjectContex的作用了。

所有我们在基类中要把这个上下文留出来,作为一个可以访问的属性。通过这个上下文,可以在自类中访问数据模型中其他表,ObjectSet 是对应当前EF实体对象,也把这个暴露给外面使用。然后就是分页和搜索的封装了。具体代码如下:

  public class BaseRepository<TEntity> where TEntity: EntityObject
{
protected RBACEntities RBACContext { get; set; }
protected ObjectSet<TEntity> DbSet { get; set; } protected virtual IQueryable<TEntity> Entities
{
get { return RBACContext.CreateObjectSet<TEntity>(); }
} public BaseRepository()
{
this.RBACContext = DbContextFactory.GetContext();
this.DbSet=RBACContext.CreateObjectSet<TEntity>();
} public IQueryable<TEntity> GetPage<TKey>(int pageIndex, int pageSize,Expression<Func<TEntity,TKey>> orderBy, out int totalRecord)
{
totalRecord = DbSet.Count();
return this.DbSet
.OrderByDescending(orderBy)
.Skip((pageIndex - ) * pageSize)
.Take(pageSize)
.AsQueryable();
} public IQueryable<TEntity> GetPage<TKey>(int pageIndex, int pageSize, Expression<Func<TEntity, TKey>> orderBy, Expression<Func<TEntity, bool>> where, out int totalRecord)
{
var res=DbSet.Where(where); totalRecord = res.Count();
return res
.OrderByDescending(orderBy)
.Skip((pageIndex - ) * pageSize)
.Take(pageSize)
.AsQueryable();
} public TEntity Add(TEntity entity,bool saveChange)
{
RBACContext.CreateObjectSet<TEntity>().AddObject(entity);
if (saveChange)
{
RBACContext.SaveChanges();
}
return entity;
} public TEntity Edit(TEntity entity, bool saveChange)
{
RBACContext.CreateObjectSet<TEntity>().Attach(entity);
RBACContext.ObjectStateManager.ChangeObjectState(entity,System.Data.EntityState.Modified);
if (saveChange)
{
RBACContext.SaveChanges();
}
return entity;
} public void Delete(TEntity entity, bool saveChange)
{
RBACContext.CreateObjectSet<TEntity>().DeleteObject(entity);
if (saveChange) { RBACContext.SaveChanges(); }
}
}

SaveChange是一个bool 类型参数,表明是否要上下文保存到数据库,如果只是修改一张表,直接保存,如果涉及多个操作,最后统一SaveChange也就实现了事务统一。

3、EF中实体序列化去除 EntityKey字段

如果直接把EF模型数据表对应的模型进行序列化,会得到很多跟EF相关的属性,要去掉这些多余的属性,就响应对序列化进行一些修改了。

这里使用的是Newtonsoft.Net进行序列化的。具体封装源码:

     public class JsonNet
{
/// <summary>
/// 将实体对象转换成Json字符串
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public static string SerializeToString(object item)
{
return JsonConvert.SerializeObject(item, Formatting.Indented,
new JsonSerializerSettings
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
ContractResolver = new ExcludePropertiesContractResolver(new List<string> { "EntityKey" }),
}); } /// <summary>
/// 将Json字符串转换成实体对象
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="jsonString"></param>
/// <returns></returns>
public static T DeserializeToEntity<T>(string jsonString)
{
return JsonConvert.DeserializeObject<T>(jsonString);
}
} public class ExcludePropertiesContractResolver : DefaultContractResolver
{
IEnumerable<string> lstExclude; public ExcludePropertiesContractResolver(IEnumerable<string> excludedProperties)
{
lstExclude = excludedProperties;
} protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
return base.CreateProperties(type, memberSerialization).ToList().FindAll(p => !lstExclude.Contains(p.PropertyName));
}
}

DB First 中对Repository 层封装的几点小记的更多相关文章

  1. 使用DapperSimpleCRUD对Repository层进行封装

    通过前面的两篇文章使用Dapper操作Mysql数据库与使用Dapper进行参数化查询,大致介绍了Dapper的一些基本操作和简单使用,在实际的使用当中,我们可以把项目简单的分为MVC+Service ...

  2. 【redis】5.spring boot项目中,直接在spring data jpa的Repository层使用redis +redis注解@Cacheable直接在Repository层使用,报错问题处理Null key returned for cache operation

    spring boot整合redis:http://www.cnblogs.com/sxdcgaq8080/p/8028970.html 首先,明确一下问题的场景 之前在spring boot整合re ...

  3. MVC架构中的Repository模式 个人理解

    关于MVC架构中的Repository模式   个人理解:Repository是一个独立的层,介于领域层与数据映射层(数据访问层)之间.它的存在让领域层感觉不到数据访问层的存在,它提供一个类似集合的接 ...

  4. PHP MVC 中的MODEL层

    Model层,就是MVC模式中的数据处理层,用来进行数据和商业逻辑的装封 三.实现你的Mode层 Model层,就是MVC模式中的数据处理层,用来进行数据和商业逻辑的装封,进行他的设计的时候设计到三个 ...

  5. SpringJdbc持久层封装,Spring jdbcTemplate封装,springJdbc泛型Dao,Spring baseDao封装

    SpringJdbc持久层封装,Spring jdbcTemplate封装,springJdbc泛型Dao,Spring baseDao封装 >>>>>>>& ...

  6. 小程序api请求层封装(Loading全局配置)

    前言 小程序开发,没有vue中的axios那么好使,请求层的封装需要自己来搞. 当然请求层的配置少不了loading,这里索性也就将loading做一个配置,避免以后重复造轮子 请求封装 小程序中有封 ...

  7. Altium 中异形焊盘异形封装的创建图文教程

    Altium 中异形焊盘异形封装的创建图文教程 一般不规则的焊盘被称为异型焊盘,典型的有金手指.大型的器件焊盘或者板子上需要添加特殊形状的铜箔(可以制作一个特殊封装代替). 如图27所示,此处我们以一 ...

  8. MVC中Model BLL层Model模型互转

    MVC中Model BLL层Model模型互转 一. 模型通常可以做2种:充血模型和失血模型,一般做法是模型就是模型,不具备方法来操作,只具有属性,这种叫做失血模型(可能不准确):具备对模型一定的简单 ...

  9. Laravel 中使用 Repository 模式

    在本文中,我会向你展示如何在 Laravel 中从头开始实现 repository 设计模式.我将使用 Laravel 5.8.3 版,但 Laravel 版本不是最重要的.在开始写代码之前,你需要了 ...

随机推荐

  1. laravel 5.1 单元测试 Cannot modify header information 错误

    运行phpunit的时候加上参数 --stderr ./vendor/bin/phpunit --stderr

  2. 【题解】Inspection UVa 1440 LA 4597 NEERC 2009

    题目传送门:https://vjudge.net/problem/UVA-1440 看上去很像DAG的最小路径覆盖QwQ? 反正我是写了一个上下界网络流,建模方法清晰易懂. 建立源$s$,向每个原图中 ...

  3. 装饰器--decorator3

    装饰器添加返回值 import time def timer(func): def wrapper(*args,**kwargs): #wrapper包装的意思 start_time = time.t ...

  4. UndertowServer+SpringMVC+Thymeleaf模板引擎构建轻量级的web项目

    这两周需要写一个页面来请求另一个服务中的接口,服务器采用了超轻量级的undertow,模板引擎采用的是Thymeleaf,在寻找页面资源位置这个地方难住了我.下面分享一下,这方面的代码. Spring ...

  5. JVM学习十二:JVM之性能监控工具

    前面我们学习了很多JVM相关的理论知识,那么本节将重点讲述的是工具的使用,正所谓:工欲善其事,必先利其器.因此,本节介绍常用的性能监控工具,用于性能监控和问题排查. 一.系统性能监控 系统性能工具用于 ...

  6. cmd下常用命令汇总

    1.获得文件夹内所有文件的文件名列表 dir *.png /b>list.txt 其中: (1)*.png表示筛选后缀为.png的文件 (2)/b为输出的模式.如下: 引用 /b 只有文件名  ...

  7. NSURLSession---iOS-Apple苹果官方文档翻译

    CHENYILONG Blog NSURLSession---iOS-Apple苹果官方文档翻译 NSURLSession 技术博客http://www.cnblogs.com/ChenYilong/ ...

  8. 【洛谷P2015】二叉苹果树

    题目描述 有一棵苹果树,如果树枝有分叉,一定是分2叉(就是说没有只有1个儿子的结点) 这棵树共有N个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1. 我们用一根树枝两端连接的结点的编号来 ...

  9. 51Nod 1256 扩展欧几里得求乘法逆元

    给出2个数M和N(M < N),且M与N互质,找出一个数K满足0 < K < N且K * M % N = 1,如果有多个满足条件的,输出最小的. Input 输入2个数M, N中间用 ...

  10. sql统计字符串出现次数技巧

    在牛客网上看到一道题,感觉挺有趣,是用sql统计字符串出现的次数. 这里提供一种思路,比如统计字符串A中子串B的出现次数: SELECT (LENGTH(A) - LENGTH(REPLACE(A, ...