专栏首页平凡少年数据访问模式之Repository模式

数据访问模式之Repository模式

数据访问层无非就是对数据进行增删改查,其中增、删、改等我们可以抽象出来写一个公共的接口或抽象类来定义这些方法,并采用一个基类实现这些方法,这样该基类派生的子类都会继承增、删、改这些方法,这样我们就避免了每个实体都要重复实现这些方法。一句话概括就是:通过接口 泛型 与ORM结合 实现了数据访问层更好的复用。

在《企业架构模式》中,译者将Repository翻译为资源库。给出如下说明:通过用来访问领域对象的一个类似集合的接口,在领域与数据映射层之间进行协调。

下面我们就用EF来实现一个简单的Repository模式 

1、我们对实体的公共操作部分,提取为IRepository接口,比如常见的增加,删除、修改等方法。如下代码

我们发现接口的泛型TEntity有一个约束需要继承BaseEntity,BaseEntity就是把实体中公共的属性抽取出来,比如:Id(主键),CreateDate(创建时间)等。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Repository.Model;
using System.Data.Entity;

namespace Repository.Data
{
    public interface IRepository<TEntity> where TEntity:BaseEntity
    {
        DbSet<TEntity> Entities { get; }
        //增加单个实体
        int Insert(TEntity entity);
        //增加多个实体
        int Insert(IEnumerable<TEntity> entities);
        //更新实体
        int Update(TEntity entity);
        //删除
        int Delete(object id);
        //根据逐渐获取实体
        TEntity GetByKey(object key);

    }
}

2、BaseEntity类

BaseEntity类中定义了所有参加数据操作实体的公共属性,因此我们把该类定义为抽象类,作为派生类的的基类。代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.DataAnnotations;

namespace Repository.Model
{
    public abstract class BaseEntity
    {
        public BaseEntity()
        {
            Id = Guid.NewGuid();
            CreateDate = DateTime.Now;
        }
        [Key]
        public Guid Id { get; set; }
        public DateTime CreateDate { get; set; }
    }
}

3、IRepository接口定义完毕,肯定需要一个雷来实现接口中的方法,下面我们定义一个抽象类EFRepositoryBase来实现该接口方法

我们用一个抽象类EFRepositoryBase来实现接口中的方法,这样派生的类都具有接口中定义的方法,也防止EFRepositoryBase直接被实例化,下面我们直接看代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Repository.Model;
using System.Data.Entity;

namespace Repository.Data
{
    public abstract class EFRepositoryBase<TEntity> : IRepository<TEntity> where TEntity:BaseEntity
    {
        DemoDbContext Db = new DemoDbContext();
       
        #region IRepository<TEntity> 成员

        public DbSet<TEntity> Entities
        {
            get { return Db.Set<TEntity>(); }
        }

        public int Insert(TEntity entity)
        {
            Db.Set<TEntity>().Add(entity);
            return Db.SaveChanges();
        }

        public int Insert(IEnumerable<TEntity> entities)
        {
            throw new NotImplementedException();
        }
        public int Update(TEntity entity)
        {
            return 0;
        }
        public int Delete(object id)
        {
            throw new NotImplementedException();
        }

        public TEntity GetByKey(object key)
        {
            return Db.Set<TEntity>().Find(key);

        }

        #endregion
    }
}

因为我们用的EF作为数据访问,因此我们需要定义一个数据上下文,代码如下

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Entity;
using Repository.Model;
using System.Data.Entity.Migrations;
using System.Data.Entity.ModelConfiguration.Conventions;

namespace Repository.Data
{
    public class DemoDbContext : DbContext
    {
        public DemoDbContext() : base("default") 
        {
            Database.SetInitializer<DemoDbContext>(new MigrateDatabaseToLatestVersion<DemoDbContext, ReportingDbMigrationsConfiguration>());
        }
        public DbSet<Member> Members { get; set; }
        public DbSet<Score> Scores { get; set; }
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
            modelBuilder.Entity<Member>().HasMany(b => b.Scores);
        }
      
    }
    internal sealed class ReportingDbMigrationsConfiguration : DbMigrationsConfiguration<DemoDbContext>
    {
        public ReportingDbMigrationsConfiguration()
        {
            AutomaticMigrationsEnabled = true;//任何Model Class的修改將會直接更新DB
            AutomaticMigrationDataLossAllowed = true;
        }
    }
}
 <connectionStrings>
    <add name="default" connectionString="Data Source=ERIC\SQLEXPRESS;Initial Catalog=EfSample;Integrated Security=True" providerName="System.Data.SqlClient" />
  </connectionStrings>

我们一共定义两个实体,一个是Members(学生)类和Scores(成绩)类,Members与Scores为一对多的关系。

4、Members类和Scores类,都要继承BaseEntity基类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.DataAnnotations.Schema;

namespace Repository.Model
{
    [Table("tb_Member",Schema="dbo")]
   public class Member:BaseEntity
    {
        public int Num { get; set; }
       public string UserName { get; set; }
       public string Sex { get; set; }
       public int Age { get; set; }
       [ForeignKey("MemberId")]
       public virtual ICollection<Score> Scores { get; set; }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.DataAnnotations.Schema;

namespace Repository.Model
{
    [Table("tb_Score",Schema="dbo")]
   public  class Score:BaseEntity
    {
       public Guid MemberId { get; set; }
       public double Scores { get; set; }
       public Guid courseId { get; set; }
    }
}

基础工作都已经完成了,下面我们来看 MemberRepository.cs类和ScoreRespository.cs类。

所有的数据操作都在EFRepositoryBase.cs中实现了,因此MemberRepository.cs和ScoreRespository.cs只需要继承EFRepositoryBase,即可实现增删改查。

1、MemberRepository.cs

MemberRepository为实体Member的操作类,因此EFRepositoryBase基类中的泛型被替换成实体Member,这样该类中就已经有了对Member的增删改查操作,我们也可以在MemberRepository中定义其他方法。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Repository.Model;

namespace Repository.Data
{
    public class MemberRepository : EFRepositoryBase<Member>, IRepository<Member>
    {
    }
    
}

2、ScoreRespository.cs

ScoreRespository与MemberRepository一样,只不过是对实体Score的操作。

3、简单测试

public void test()
        {
            MemberRepository mr = new MemberRepository();
            var entity = new Member()
            {
                UserName = "eric",
                Age = 25,
                Sex = "男"
            };
            mr.Insert(entity);

            var score = new Score()
            {
                MemberId = entity.Id,
                Scores = 80,
                courseId = Guid.NewGuid()
            };
            ScoreRespository sr = new ScoreRespository();
            sr.Insert(score);
        }

我们发现数据操作成功。

一般Repository都会跟Unit of Work模式联合使用,如果你有好的学习资料欢迎分享,Unit of Work模式曾看了一天也没有理解其精髓。

每天学习一点点,每天进步一点点。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • EntityFramework使用总结(与MVC4.0实现CURD操作)

    本篇文介绍一下Entity Framework Code First的简单用法,通过一个学生信息的增删查改来学习Entity Framework的使用及与存储过...

    写代码的猿
  • MVC4+WebApi+Redis Session共享练习(上)

    这几天生病了,也没有心情写博客,北京医院真心伤不起呀,钱不少花,病没治好,还增加了新病,哎不说了,周末还得去大医院检查一下,趁女盆友还没有回来,把前几天写的东西...

    写代码的猿
  • Knockout简单用法

        在最近做的一个项目中,页面数据全部通过js ajax调用webapi接口获取,也就是说页面的数据全部使用javascript脚本填充,这就想到了使用一个...

    写代码的猿
  • WCF系列教程之WCF中的会话

    本文参考自http://www.cnblogs.com/wangweimutou/p/4516224.html,纯属读书笔记,加深记忆 一、WCF会话简介 1、...

    郑小超.
  • Linux中的命令格式及使用帮助

    版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/...

    魏晓蕾
  • 动态调用WebService

    http://linglong117.blog.163.com/blog/static/277145472009127514463/

    跟着阿笨一起玩NET
  • 刨根问底儿————解析Java代码,看看toString的秘密

    在main方法中执行第一个语句System.out.println("love "+new ToStringTest() ),语句由内向外执行,先执行new T...

    泰斗贤若如
  • 两个关于字符串的经典例子

    示例1: ==运算符 public static void test(){ String x = "hello"; String y = "world"; S...

    java达人
  • Java中lambda表达式详解

    上面的代码中,e是一个lambda的对象,根据java的继承的特性,我们可以说e对象的类型是继承自eat接口。而e1是一个正常的匿名类的对象.

    付威
  • 数据加密技术之MD5加密

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明...

    bering

扫码关注云+社区

领取腾讯云代金券