mvc3+ef4.1 Learning Series (eight)-----using repository and Unit of work refactoring project

Source: Internet
Author: User

The Project's most basic thing is over, but now our project is not perfect. it is not conducive to testing repetitive code multilayer and layer coupling between layers is not conducive to expansion and so on. this chapter of today is mainly to solve these problems. Solve these problems, oneself also produced a lot of questions, understanding is not very thorough, I hope my question can be answered here ~ ~

I. Introduction to the Model

1.Repository

In Enterprise architecture mode, the domain is coordinated with the data mapping layer through an interface that is used to access a similar collection of domain Objects. Also please refer to this P of EAA detailed introduction

Then say my feelings and doubts about this how all feel this repository is the previous DAO (dal) layer ~ ~ But it is through the interface generic and ORM combination to achieve better reuse don't know

2.Unit of work

The Unit of work definition and interpretation are described First. The main solution is to change the data storage and transaction processing when there are multiple operations. The unit of work is a record of all the object model modified information, at the time of submission, the modification at once, and the results are synchronized to the Database. In fact, we can find that DbContext already has such a function ~ ~ to a large extent achieved unit of work~ because we savechange ()

Subset submitting the data

3. Overall overview

Use repository and unit of work to create an abstraction layer between the data layer and the business logic Layer. It will help us isolate the changes and be more conducive to testing.

Below are the differences between using repository and unit of work and not using the diagram illustrated below

Two. start of transformation

Let's go back to the first student controller and forget about what friends can look at this section-------student controller we put

Private Schoolcontext db = new Schoolcontext ();

It's written on each controller. the declaration period is fully coupled with the controller

1. Create student Repository interface

Using System;
Using System.Collections.Generic;
Using system.linq;
Using system.web;
Using contosouniversity.models;

Namespace Contosouniversity.dal
{
public interface Istudentrepository:idisposable
{
Ienumerable<student> getstudents ();
Student Getstudentbyid (int studentid);
void Insertstudent (Student Student);
void Deletestudent (int studentid);
void Updatestudent (Student Student);
void Save ();
}
}

2. Implementing the interface

Using System;
Using System.Collections.Generic;
Using system.linq;
Using system.data;
Using contosouniversity.models;

Namespace Contosouniversity.dal
{
public class studentrepository:istudentrepository, IDisposable
{
Private Schoolcontext context;

Public Studentrepository (schoolcontext Context)
{
This.context = context;
}

Public ienumerable<student> getstudents ()
{
Return to Context. Students.tolist ();
}

Public Student Getstudentbyid (int id)
{
Return to Context. Students.find (id);
}

public void Insertstudent (Student Student)
{
Context. Students.add (student);
}

public void Deletestudent (int Studentid)
{
Student Student = Context. Students.find (studentid);
Context. Students.remove (student);
}

public void Updatestudent (Student Student)
{
Context. Entry (student). State = entitystate.modified;
}

public void Save ()
{
Context. SaveChanges ();
}

private bool disposed = false;

protected virtual void Dispose (bool Disposing)
{
If (!this.disposed)
{
If (disposing)
{
Context. Dispose ();
}
}
this.disposed = true;
}

public void Dispose ()
{
Dispose (true);
Gc. SuppressFinalize (this);
}
}
}

3. Retrofit Student Controller

View Code

Through the above operation now our controller is for an interface and no longer directly through the dbcontext of course if we use the IOC container here will be able to achieve better decoupling we can look at

This article of quite Unruly's soul

4. Problems arising after the transformation

1. The dbcontext that we were supposed to implement in the controller is now in the repository because the project will have multiple repository so there will be multiple dbcontext! This is a time when we have

A complex logic to use multiple Repository, such as I casually say an example ~ ~ such as adding an order to update a detailed order and then delete a customer hypothesis this series of logic is together here will use three Repository we want to invoke a different Reposito SAVE in Ry () at this point we are going to do multiple commits and no longer a unified transaction. efficiency integrity is greatly reduced. Instead of losing

DbContext bring the benefits of unit of work ~ ~ It's okay, we're going to implement unit of work to retrofit the problem later.

2. The second problem is also a very serious one. we used to look for students in search sort and Pagination.

var students = from S in Context. Students
Select s;
If (! String.IsNullOrEmpty (searchstring))
{
Students = Students. Where (s = = S.lastname.toupper (). Contains (searchstring.toupper ())
|| S.firstmidname.toupper (). Contains (searchstring.toupper ()));
}

And now It's become

var students = from S in studentrepository.getstudents ()
Select s;

This is a serious problem IQueryable 而现在的是  .IEnumerable  变成了数据直接全部查找出来  所以再这里 我觉得Repository的查找 应该是返回IQueryable

Instead ofIEnumerable 

要不然There was the first question I had in the Text. it's not just an ordinary crud, it's a normal data access Layer.

andRepository用法我觉得应该是 返回IQueryable 参数的接受应该是一个表达式树  不知道大家是否认同?希望大家帮我解决下疑惑 谢谢~

The following public generic Repository will embody this

THREE. Create a public repository

Look at the students above us, Repository. if we were to write the course, the code would be very similar, so we use generic injection to implement multiplexing. a generic interface and generic class should be implemented here

But the original is not implemented interface ~ only a class

Let me see this class.

Namespace Contosouniversity.dal
{
public class genericrepository<tentity> where Tentity:class
{
Internal Schoolcontext context;
Internal Dbset<tentity> DbSet;

Public Genericrepository (schoolcontext Context)
{
This.context = context;
This.dbset = Context. Set<tentity> ();
}

Public virtual ienumerable<tentity> Get (
expression<func<tentity, bool>> filter = null,
func<iqueryable<tentity>, iorderedqueryable<tentity>> = 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 (~ = = Null)
{
Return (query). ToList ();
}
Else
{
Return query. ToList ();
}
}

Public virtual TEntity GetByID (object id)
{
return Dbset.find (id);
}

Public virtual void Insert (TEntity Entity)
{
Dbset.add (entity);
}

Public virtual void Delete (object Id)
{
TEntity Entitytodelete = Dbset.find (id);
Delete (entitytodelete);
}

Public virtual void Delete (TEntity Entitytodelete)
{
If (context. Entry (entitytodelete). state = = Entitystate.detached)
{
Dbset.attach (entitytodelete);
}
Dbset.remove (entitytodelete);
}

Public virtual void Update (TEntity Entitytoupdate)
{
Dbset.attach (entitytoupdate);
Context. Entry (entitytoupdate). State = entitystate.modified;
}
}
}

This is the way to focus Here.

 public virtual ienumerable<tentity> Get (
expression<func<tentity, bool>> filter = Nu ll,
func<iqueryable<tentity>, iorderedqueryable<tentity>> = 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 (out of! = Null)
{
return by (query). ToList ();
}
Else
{
return query. ToList ();
}
}

or, as I said above, I think it should be returned, IQueryable so I think we should get rid of the last One. ToList and return IQueryable

And then look at this method the first one to accept an expression tree is actually the filter condition the second is a delegate that is primarily used to sort the third accept to be greedy load which navigation properties can be separated by commas

And here take advantage of the next 4.0 of the function can give the parameter a default value is empty how to use this method will be written in the following ~ ~

There's One more place that I didn't mention Before.

     Public virtual void Delete (TEntity Entitytodelete)
{
If (context. Entry (entitytodelete). state = = Entitystate.detached)
{
Dbset.attach (entitytodelete);
}
Dbset.remove (entitytodelete);
}

This Dbset.attach (entitytodelete); Represents the addition of an object to the database context managed by DbContext I have a little question here. is there any benefit of not adding this judgment?

Four. Create a Unit of work Class

The primary purpose of creating this class is to ensure that multiple repository can share a database context let's look at this class

Namespace Contosouniversity.dal
{
public class Unitofwork:idisposable
{
Private Schoolcontext context = new Schoolcontext ();
Private Genericrepository<department> departmentrepository;
Private Genericrepository<course> courserepository;

Public genericrepository<department> Departmentrepository
{
Get
{

if (this.departmentrepository = = Null)
{
This.departmentrepository = new Genericrepository<department> (context);
}
Return departmentrepository;
}
}

Public genericrepository<course> Courserepository
{
Get
{

if (this.courserepository = = Null)
{
This.courserepository = new Genericrepository<course> (context);
}
Return courserepository;
}
}

public void Save ()
{
Context. SaveChanges ();
}

private bool disposed = false;

protected virtual void Dispose (bool Disposing)
{
If (!this.disposed)
{
If (disposing)
{
Context. Dispose ();
}
}
this.disposed = true;
}

public void Dispose ()
{
Dispose (true);
Gc. SuppressFinalize (this);
}
}
}

Write the class that wants the unit of work to help you control the whole. here we only wrote Two.

Private Schoolcontext context = new Schoolcontext ();
Private Genericrepository<department> departmentrepository;
Private Genericrepository<course> courserepository;

Implement Read-only Properties

Public genericrepository<department> Departmentrepository
{
Get
{

if (this.departmentrepository = = Null)
{
This.departmentrepository = new Genericrepository<department> (context);
}
Return departmentrepository;
}
}

And finally the release of the Save and the resources

okay, now look at how to use This.

Five. Change the course controller

Original Controller Code

The original demo does not reflect the benefits of using unit of work because this example does not appear to have a logical use of multiple repositories of hope you understand this ~ ~ and so on after the article

I'm going to write a full demo to illustrate This. here, let's see what's going on Here.

Six. questions about the EF+MVC framework

1. Is it necessary to implement the Iunitofwork interface? The code probably does.

public interface Iunitofwork

{

void Save ();

Istudentrepository studentrepository {get;}

}

Implementing interfaces

public class Unitofwork:iunitofwork

{

Private SchoolEntities context = new SchoolEntities ();

Private Istudentrepository studentrepository;

Public Istudentrepository Studentrepository

{

Get

{

if (this.studentrepository = = Null)

{

This.studentrepository = new Studentrepository (context);

}

Return studentrepository;

}

}

public void Save ()

{

Context. SaveChanges ();

}

}

Controller

Private Iunitofwork unitofwork;

Public Studentcontroller (): this (new unitofwork ())

{

}

Public Studentcontroller (iunitofwork Unitofwork)

{

This.unitofwork = unitofwork;

}

2. Whether it is necessary to add a service layer services this layer between the controller and the dal, which is called by unitofwork, and so on is written on the servie, so the code in the controller will become very small, the personal feel should be added service layer, but What are the benefits of adding a IService interface to this interface? I've always felt that the interface is only for the data access Layer.

3. Here we are using the unit of work to complete the consistency of the transaction before I used

Using (TransactionScope transaction = new TransactionScope ()) {
....


Use this to achieve transactional consistency what do you think about this and unit of work? I have not studied this ~ but the small city years to this did a very good introduction thanks to the small city ~ we can refer to his this article

4. Our caches such as mongodb, which layer is it better to write to?

Six. Summary

After refactoring the code finally some of the items look like ~ ~ The following section tells about some of the other features of ef, such as executing SQL statements directly, and closing the trace State.

mvc3+ef4.1 Learning Series (eight)-----using repository and Unit of work refactoring project

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.