在数据库表创建完成的情况下,使用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. C++时间

    C++时间 头文件 chrono, 命名空间 std. 现在时间 std::chrono::system_clock::now() 返回系统时钟的当前时间 时钟 std::chrono::system ...

  2. duilib CDateTimeUI 在Xp下的bug修复

    转自:http://my.oschina.net/u/343244/blog/370131 CDateTimeUI 的bug修复.修改CDateTimeWnd的HandleMessage方法 ? 1 ...

  3. 题解 P3153 【[CQOI2009]跳舞】

    P3153 [CQOI2009]跳舞 题目描述 一次舞会有n个男孩和n个女孩.每首曲子开始时,所有男孩和女孩恰好配成n对跳交谊舞.每个男孩都不会和同一个女孩跳两首(或更多)舞曲.有一些男孩女孩相互喜欢 ...

  4. eclipse+myeclipse 使用技巧备忘

    myeclipse 导入多模块maven项目 https://blog.csdn.net/jack85986370/article/details/51371853 maven项目在eclipse的l ...

  5. 关于HttpWebRequest发生服务器协议冲突的解决办法

    WinForm下的app.config文件中添加: <system.net>    <settings>      <httpWebRequest useUnsafeHe ...

  6. C++面试中可能考察的基础知识(1)

    1 C++中允许函数的嵌套调用,但不允许函数的嵌套定义 2 构建派生类对象时,先调用基类的构造函数,在调用成员对象的构造函数,最后调用派生类构造函数. 3 volatile关键字 volatile提醒 ...

  7. Java 中的几种线程池这么用才是对的

    为什么要使用线程池 虽然大家应该都已经很清楚了,但还是说一下.其实归根结底最主要的一个原因就是为了提高性能. 线程池和数据库连接池是同样的道理,数据库连接池是为了减少连接建立和释放带来的性能开销.而线 ...

  8. 【洛谷 P2472】 [SCOI2007]蜥蜴 (最大流)

    题目链接 简单网络流. 源点向蜥蜴连流量为\(1\)的边. 能跳出去的点向汇点连流量为\(INF\)的边. 把每个点拆成\(2\)个点,\(O(n^4)\)枚举两两点,如果距离小于等于\(d\),就互 ...

  9. POJ 3734 Blocks (矩阵快速幂)

    题目链接 Description Panda has received an assignment of painting a line of blocks. Since Panda is such ...

  10. 39、请用代码简答实现stack

    栈和队列是两种基本的数据结构,同为容器类型.两者根本的区别在于: stack:后进先出 queue:先进先出 PS:stack和queue是不能通过查询具体某一个位置的元素而进行操作的.但是他们的排列 ...