DB First 中对Repository 层封装的几点小记
在数据库表创建完成的情况下,使用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 层封装的几点小记的更多相关文章
- 使用DapperSimpleCRUD对Repository层进行封装
通过前面的两篇文章使用Dapper操作Mysql数据库与使用Dapper进行参数化查询,大致介绍了Dapper的一些基本操作和简单使用,在实际的使用当中,我们可以把项目简单的分为MVC+Service ...
- 【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 ...
- MVC架构中的Repository模式 个人理解
关于MVC架构中的Repository模式 个人理解:Repository是一个独立的层,介于领域层与数据映射层(数据访问层)之间.它的存在让领域层感觉不到数据访问层的存在,它提供一个类似集合的接 ...
- PHP MVC 中的MODEL层
Model层,就是MVC模式中的数据处理层,用来进行数据和商业逻辑的装封 三.实现你的Mode层 Model层,就是MVC模式中的数据处理层,用来进行数据和商业逻辑的装封,进行他的设计的时候设计到三个 ...
- SpringJdbc持久层封装,Spring jdbcTemplate封装,springJdbc泛型Dao,Spring baseDao封装
SpringJdbc持久层封装,Spring jdbcTemplate封装,springJdbc泛型Dao,Spring baseDao封装 >>>>>>>& ...
- 小程序api请求层封装(Loading全局配置)
前言 小程序开发,没有vue中的axios那么好使,请求层的封装需要自己来搞. 当然请求层的配置少不了loading,这里索性也就将loading做一个配置,避免以后重复造轮子 请求封装 小程序中有封 ...
- Altium 中异形焊盘异形封装的创建图文教程
Altium 中异形焊盘异形封装的创建图文教程 一般不规则的焊盘被称为异型焊盘,典型的有金手指.大型的器件焊盘或者板子上需要添加特殊形状的铜箔(可以制作一个特殊封装代替). 如图27所示,此处我们以一 ...
- MVC中Model BLL层Model模型互转
MVC中Model BLL层Model模型互转 一. 模型通常可以做2种:充血模型和失血模型,一般做法是模型就是模型,不具备方法来操作,只具有属性,这种叫做失血模型(可能不准确):具备对模型一定的简单 ...
- Laravel 中使用 Repository 模式
在本文中,我会向你展示如何在 Laravel 中从头开始实现 repository 设计模式.我将使用 Laravel 5.8.3 版,但 Laravel 版本不是最重要的.在开始写代码之前,你需要了 ...
随机推荐
- UESTC--1682
原题链接: 分析:求最小周期的应用. #include<cstdio> #include<cstring> #include<cmath> #include< ...
- (转)C++常见问题: 字符串分割函数 split
http://www.cnblogs.com/dfcao/p/cpp-FAQ-split.html C++标准库里面没有字符分割函数split ,这可太不方便了,我已经遇到>3次如何对字符串快速 ...
- (转) 使用vivado创建工程 3
Create a Hello World application In this experiment we will use Xilinx SDK to create a simple Hello ...
- tf.session.run()单函数运行和多函数运行区别
tf.session.run()单函数运行和多函数运行区别 觉得有用的话,欢迎一起讨论相互学习~Follow Me problem instruction sess.run([a,b]) # (1)同 ...
- awk是全局周期
需要折行时需要用转译符,转译回车,回车是提交命令 \ 如果你的命令中有单引号也可以 awk 支持C语言 awk '{name[$1]=name[$1]+$2} END{f ...
- ① 设计模式的艺术-07.适配器(Adapter)模式
什么是适配器模式? 将一个类的接口转换成客户希望的另外一个接口.Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以在一起工作. 模式中的角色 目标接口(Target):客户所期待的接口 ...
- [Mac]一些命令技巧
Git相关 mac下git默认不区分大小写,通过下面脚本可以改变 #!/bin/bash # 让git区分大小写 cd 'path-of-project' git config core.ignore ...
- oschina ios开发学习
应该跟android版的类似,例如服务器端在oschina-prefix.pch里 #define api_news_list @"http://www.oschina.net/action ...
- Java生成验证码简记
验证码定义 验证码(captcha):是一种区分用户是计算机还是人的公共全自动程序. 作用:可以防止恶意破解密码.刷票.灌水,有效防止对某一个特定注册用户用特定程序进行暴力破解的登录尝试. 验证码交互 ...
- 解决pl/sq可视化工具的中文乱码问题
解决pl/sql中文乱码问题 问题:pl/sql的中文都显示为“?”,怎么能显示成中文呢? 1. 执行sql语句 select * from V$NLS_PARAMETERS NLS_LANGUAG ...