數據訪問模式之Repository模式


數據訪問層無非就是對數據進行增刪改查,其中增、刪、改等我們可以抽象出來寫一個公共的接口或抽象類來定義這些方法,並采用一個基類實現這些方法,這樣該基類派生的子類都會繼承增、刪、改這些方法,這樣我們就避免了每個實體都要重復實現這些方法。一句話概括就是:通過接口 泛型 與ORM結合 實現了數據訪問層更好的復用。

在《企業架構模式》中,譯者將Repository翻譯為資源庫。給出如下說明:通過用來訪問領域對象的一個類似集合的接口,在領域與數據映射層之間進行協調。

下面我們就用EF來實現一個簡單的Repository模式 

1、我們對實體的公共操作部分,提取為IRepository接口,比如常見的增加,刪除、修改等方法。如下代碼

我們發現接口的泛型TEntity有一個約束需要繼承BaseEntityBaseEntity就是把實體中公共的屬性抽取出來,比如: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;
        }
    }
}
DemoDbContext()

 

 <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; }
    }
}
Member
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; }
    }
}
Score

基礎工作都已經完成了,下面我們來看 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模式曾看了一天也沒有理解其精髓。

每天學習一點點,每天進步一點點。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM