简体   繁体   中英

Creating a simple unit of work with Entity Framework and no repository

I've been trying to implement a .net MVC Unit of Work API (rather than creating a separate repository), but it doesn't feel right. Am I going about this the correct way?

BaseController

public class BaseController : ApiController
    {
        protected DBEntities _dbEntities;

        protected override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            _dbEntities = new DBEntities();
        }

        protected override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            _dbEntities.SaveChanges();
        }
    }

MyController

public class MyController : BaseController
{
    public HttpResponseMessage PutMyObject(int id, int id2)
    {
        if (id != 0)
        {
            var myObject = _dbEntities.MyObjects.Where(x => x.id == id);
            if (myObject.Count() > 0)
            {
                MyObject temp = myObject.SingleOrDefault();
                temp.Processed = true;
                return Request.CreateResponse(HttpStatusCode.OK);
            }
            else
            {
                return Request.CreateErrorResponse(HttpStatusCode.NotFound);
            }
        }
        else
        {
            /* do some other stuff */
        }
    }             

}

My thinking around this is that the controller action is a single Unit of Work. The database connection is opened when the controller action starts, and SaveChanges is called once the response is returned.

Am I going about this in the correct manner? do i need to dispose of _dbentities after savechanges is called within the BaseController? (or is this a better question for code review exchange)

I think, It would be a bad design for OOP architecture and flexibility. Because, you have to provide database actions in your main MVC project and you couldn't provide them in other layers. So, you should provide repository pattern and you should access the repositories from main MVC project and other required projects. So, I suggest you to handle _dbEntities object in a singleton class for per thread.

Sample singleton class would be like this;

public class UnitOfWorkSampleContextBase : IDisposable
{
    [ThreadStatic]
    private static UnitOfWorkSampleContextBase _instance;

    public static UnitOfWorkSampleContextBase Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = new UnitOfWorkSampleContextBase();
            }
            return _instance;
        }
    }

    public SampleDbContext Context { get; private set; }

    private UnitOfWorkSampleContextBase()
    {

    }

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

    public void ResolveContext()
    {
        Context = new SampleDbContext(ConfigurationManager.ConnectionStrings["MainDatabase"].ConnectionString);
    }

    public void Dispose()
    {
        Context.Dispose();
        Context = null;
    }
}

And you can create the DbContext like this;

UnitOfWorkSampleContextBase.Instance.ResolveContext();

Then, you can perform actions in context like this;

var context = UnitOfWorkSampleContextBase.Instance.Context;
var records = context.sampleEntities.ToList();

Finally, you can commit and dispose the context like this;

UnitOfWorkSampleContextBase.Instance.Commit();
UnitOfWorkSampleContextBase.Instance.Dispose();

The singleton class should be in repository or base layer to be accessed desired repository classes.

Note : If you are using CastleWindsor or something like that, creating and commiting the context would be better in an interceptor. Also, it is very important that the singleton context class should be initialized for per thread.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM