MVC 实现仓储和工作单元模式分析

http://www.cnblogs.com/haogj/archive/2012/05/01/2476595.html

仓储和工作单元模式用来在数据访问层和业务逻辑层之间创建抽象层。实现这些模式有助于隔离数据存储的变化,便于自动化的单元测试或者测试驱动的开发 ( TDD )。

仓储(Repository):数据访问层和业务逻辑层之间创建抽象层,消除了她们间的直接依赖,使开发更具有柔性和扩展性。

泛型仓储:不必写大量重复代码

工作单元模式(unit of work) :确保所有的仓储都使用同样的数据库上下文。

对每一个实体类型创建一个仓储将会导致大量重复代码。还会带来部分更新的问题。例如,假设在一个事务中更新两个不同的实体。 如果每一个仓储使用不同的数据库上下文实例,一个可能成功了,另外一个失败了。一种减少冗余代码的方式是使用泛型仓储,另一种方式是使用工作单元类来确保所有的仓储都使用同样的数据库上下文 ( 来协调所有的更新 )。

了解泛型http://www.tracefact.net/CSharp-Programming/Csharp-generics.aspx

public class SortHelper<T> where T:IComparable {
    // CODE:实现略
}

泛型类是一个模板类,它对于在执行时传递的类型参数是一无所知的,也不会做任何猜测

where T:IComparable 是对泛型类的约束,泛型类T必须实现IComparable接口

SortHelper<T> 是该泛型类T可以在类SortHelper中使用

 泛型类T在整个类中作为参数

public class SuperCalculator<T> where T:IComparable {
    // CODE:略

    public void SpeedSort(T[] array) {      
        // CODE:实现略
    }
}

泛型类T在类的一个方法中作为参数

public class SuperCalculator{
    // CODE:其他实现略

    public void SpeedSort<T>(T[] array) where T : IComparable {
        // CODE:实现略
    }
}

Book[] bookArray = new Book[2];

Book book1 = new Book(124, "C# 3.0揭秘");
Book book2 = new Book(45, ".Net之美");

SuperCalculator calculator = new SuperCalculator();
calculator.SpeedSort<Book>(bookArray);

Queryable<T>(IEnumerable<T>的一个子接口),用于查询关系数据存储。C# 和 Visual Basic 编译器会将针对此类数据源的查询编译为代码,该代码在运行时将生成一个表达式目录树。然后,查询提供程序可以遍历表达式目录树数据结构,并将其转换为适合于数据源的查询语言。
而IEnumerable<T>在编译的时候,会直接生产代码,不会生产表达式目录树。

string[] arry = new string[] { "aa","bb","cc","dd"};
            arry.Where(s => s.Length == 2).OrderByDescending(s => s).Select(s => s);
            var b=arry.AsQueryable();
            b.Where(s => s.Length == 2).OrderByDescending(s => s).Select(s => s);

如果是IEnumerable<T>的话

Where<T>( this IEnumerable<T>, Func<T, bool> ),//Where<T>是说在Where方法中有泛型T类型的参数,this IEnumerable<T> 扩展方法,Fun<T,bool>T为参数,bool为返回类型,关于Fun委托http://hi.baidu.com/jiuyouyingling/item/fc7beac0bc705d48a9ba9456

OrderByDescending<TSource,TKey>( this IEnumerable<TSource>,Func<TSource,TKey> ),

Select<TSource,TResult>( this IEnumerable<TSource>, Func<TSource,TResult> )

而IQueryable<T>会在Func<>外面包装一层Expression<>,

Where<T>( this IEnumerable<T>,Expression<Func<T, bool>> ),

OrderByDescending<TSource,TKey>( this IEnumerable<TSource>,Expression<Func<TSource,TKey>>),

Select<TSource,TResult>( this IEnumerable<TSource>, Expression<Func<TSource,TResult>> )

 

在GenericRepository.cs页面中

public virtual IEnumerable<TEntity> Get(
            Expression<Func<TEntity, bool>> filter = null,
            Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
            string includeProperties = "")
        {
            IQueryable<TEntity> query = dbSet;

            if (filter != null)
            {
                query = query.Where(filter);
            }

            foreach (var includeProperty in includeProperties.Split
                (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
            {
                query = query.Include(includeProperty);
            }

            if (orderBy != null)
            {
                return orderBy(query).ToList();
            }
            else
            {
                return query.ToList();
            }
        }

代码 Expression<Func<TEntity, bool>> filter  表示调用方需要提供一个基于 TEntity 类型的 Lambda 表达式,表达式将会返回 bool 类型的值。例如,如果仓储实例化为 Student 类型,调用的方法可能为 filter 传递的参数为  student => student.LastName == "Smith"
代码 Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy  也表示调用方需要提供一个 Lambda 表达式,在这里,表达式是 TEntity 类型的 IQueryable 对象。返回排序版本的 IQueryable 对象。例如,如果仓储实例化为 Student 实体类型,代码为 orderBy 参数传递的参数可能为 q => q.OrderBy(s => s.LastName)  。

在CourseController.cs文件中对上面进行调用

public ActionResult Index(int? SelectedDepartment)
        {
            var departments = unitOfWork.DepartmentRepository.Get(
                orderBy: q => q.OrderBy(d => d.Name));

//departments就是上面的
IEnumerable<TEntity>,即IEnumerable<Department>
//unitOfWork.DepartmentRepository返回类型GenericRepository<Department>,IEntity在这个方法中为Department
ViewBag.SelectedDepartment = new SelectList(departments, "DepartmentID", "Name", SelectedDepartment);

int departmentID = SelectedDepartment.GetValueOrDefault();
return View(unitOfWork.CourseRepository.Get(
filter: d
=> !SelectedDepartment.HasValue || d.DepartmentID == departmentID,
orderBy: q
=> q.OrderBy(d => d.CourseID),
includeProperties:
"Department"
));
}
// Expression<Func<TEntity, bool>> filter 
//filter:d=>!SelectedDepartment.
HasValue || d.DepartmentID == departmentID,
//d为Department类型对象,Fun委托的返回类型bool,filter被Where方法调用,调用后返回IEnumerable<Department>,添加Expression<>外壳,大概就是把类型转换为IQueryable<Department>
//Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
//return orderBy(query).ToList();从这可以看出orderBy调用IQueryable<Department>类型参数,正好是上面filter的返回类型,orderBy方法调用之后返回
IOrderedQueryable<Department>,最后ToList()返回的是IEnumerable<Deaprtment>

在 Enumerable 类中调用 Where 方法时,参数是委托类型 System.Func<T, TResult>

System.Linq.Queryable 类中调用相同的方法时,则参数类型是System.Linq.Expressions.Expression<Func>,其中 Func 是包含至多十六个输入参数的任何 Func 委托

在调用 Get 方法的时候,你可以不提供这些参数,而通过方法返回的 IEnumerable 集合进行过滤和排序,但是排序和过滤将会在 Web 服务器的内存中进行。通过使用这些参数,可以使这些工作在数据库中进行而不是在 Web 服务器上进行。另外一种替代方式是为特定的实体类型创建派生类,增加特定的 Get 方法,诸如 GetStudentsInNameOrder 或者 GetStudentsByName。然而,在复杂的应用中,这会导致大量的派生类和特定方法,在维护的时候会导致大量的工作。
在 GetByID, Insert 和 Update 中的方法如同在非泛型方法中一样简单 ( 在 GetByID 方法扎没有提供预先加载参数,因为不能对 Find 方法进行预先加载 )。
 IEnumerable与IQueryable:http://www.cnblogs.com/FlyEdward/archive/2010/02/01/Linq_ExpressionTree2.html

http://www.cnblogs.com/hiteddy/archive/2011/10/01/Difference_among_IQueryable_IEnumeralb_IList_in_Entity_Framework.html

 

  1. IQueryable和IEnumerable都是延时执行(Deferred Execution)的,而IList是即时执行(Eager Execution)
  2. IQueryable和IEnumerable在每次执行时都必须连接数据库读取,而IList读取一次后,以后各次都不需连接数据库。前两者很容易造成重复读取,性能低下,并且可能引发数据不一致性
  3. IQueryable和IEnumerable的区别:IEnumberalb使用的是LINQ to Object方式,它会将AsEnumerable()时对应的所有记录都先加载到内存,然后在此基础上再执行后来的Query。所以上述TestIEnumerable例子中执行的SQL是"select top(5) ...",然后在内存中选择前两条记录返回。
  4. 一般我们的查询都是IQueryable,每次调用都要重新查询。

     5. IQueryable接口与IEnumberable接口的区别:  IEnumerable<T> 泛型类在调用自己的SKip 和 Take 等扩展方法之前数据就已经加载在本地内存里了,而IQueryable<T> 是将Skip ,take 这些方法表达式翻译成T-SQL语句之后再向SQL服务器发送命令,它并不是把所有数据都加载到内存里来才进行条件过滤。

     http://www.cnblogs.com/fly_dragon/archive/2011/02/21/1959933.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值