• 关于EF Unit of Work Repository的简单用法


    其实ef本身就是unit of work+repository的

    其中继承自DbContext的类就是unit of work

    context中的DbSet<T>属性就是repository,你也可以不建那些属性,而使用context.Set<T>来获取一个DbSet<T>

    如果直接在逻辑层就ef了,一来可能觉得会与ef绑的太紧,二来可能mock的难度会变大。所以有时候还是希望逻辑层引用的是自己定义的unit of work接口和repository接口

    先来看这两个接口吧

    public interface IUnitOfWork
    {
        IRepository<T> GetRep<T>() where T : class;
    
        int Comment();
    }
    
    public interface IRepository<T> : IQueryable<T>
        where T : class
    {
        T Add(T obj);
    }
    
    
    repository我只写了一个add方法做为说明,你可以写更多的方法
    public class DatabaseContext : DbContext, IUnitOfWork
    {
        public IRepository<T> GetRep<T>() where T : class
        {
            return null;
        }
    
        public int Comment()
        {
            return this.SaveChanges();
        }
    }
    建一个ef的context,继承DbContext的同时,实现IUnitOfWork
    其中的comment方法,直接调用ef的savechanges,其实要是偷懒,直接把接口里的comment命名成savechanges就完事
    剩下就是得实现这个getrep<T>的方法了。
    
    
    我们对外提供的是IRepository,而我们有的是ef的DbSet,俩边接口不匹配,祭出适配器模式。
    
    
    public class RepositoryAdapter<T> : IRepository<T>
        where T : class
    {
        private DbContext context;
    
        private IDbSet<T> set;
    
        public RepositoryAdapter(DbContext context, IDbSet<T> set)
        {
            this.context = context;
            this.set = set;
        }

    ……

    建一个适配器类,构造的时候接收context和dbset

    之后,我们要实现IRepository的方法

    public T Add(T obj)
    {
        return set.Add(obj);
    }

    把他导向到dbset的方法去即可

    因为,我们的IRepository是集成了IQueryable的,还得实现这些

    public IEnumerator<T> GetEnumerator()
    {
        return set.GetEnumerator();
    }
    
    IEnumerator IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }
    
    public Expression Expression
    {
        get
        {
            return set.Expression;
        }
    }
    
    public Type ElementType
    {
        get
        {
            return set.ElementType;
        }
    }
    
    public IQueryProvider Provider
    {
        get
        {
            return set.Provider;
        }
    }

    统统导向到dbset的方法去

    我们让context的方法返回这个适配器

    public IRepository<T> GetRep<T>() where T : class
    {
        return new RepositoryAdapter<T>(this, this.Set<T>());
    }

    使用是uow.GetRep<T>().Where(x=>x…….)各种where,first,count,any,只要是IQueryable支持的都可以正常使用

    并且根据你IRepository中定义的方法,还可以add,delete之类的

    但是有一个ef的方法在这里是不行的,那就是Include。

    普通的where之类的方法,看源码

    image

    他是用source的provider去走。

    这里,source是我们的IRepository,实际是RepositoryAdapter,adapter中的provider,我们返回的是dbset的provider,所以他可以正常的走到dbset去查库

    但是,我们看include

    image

    include 并没有走provider,而是要看source是不是DbQuery<T>或者ObjectQuery<T>,我们这里自然都不是,所以include没能正确的导向到dbset的include去

    我们可以自己写一个扩展方法

    public static IQueryable<T> Include<T>(this IRepository<T> source, string path) where T : class
    {
        var s = source as RepositoryAdapter<T>;
        if (s != null)
        {
            return s.Set.Include(path);
        }
        return source;
    }

    为了能访问到source的dbset,我们得把dbset用只读属性公开出来。

    这样,我们就可以正确的把include也导向到dbset的include了。

    如果你要换orm了,你需要为新的orm开发对应的适配器类

  • 相关阅读:
    342. Power of Four(One-line)
    mysql的启动,停止与重启
    PHP学习笔记之interface关键字
    PHP学习笔记之析构函数以及static,self,parent关键字
    每天一个linux命令(1):ln 命令
    MySQL学习笔记:regexp正则表达式
    AARRR:数据运营模型
    MySQL学习笔记:从一个表update到另外一个表
    MySQL学习笔记:计算机服务中找不到MySQL服务
    MySQL学习笔记:insert into select
  • 原文地址:https://www.cnblogs.com/czcz1024/p/4089589.html
Copyright © 2020-2023  润新知