1

In my ASP.NET MVC application I need to implement persistence of data. I've choose Entity Framework for its ability to create classes, database tables and queries from entity model so that I don't have to write SQL table creation or Linq to SQL queries by hand. So simplicity is my goal.

My approach was to create model and than a custom HttpModule that gets called at the and of each request and that just called SaveChanges() on the context. That made my life very hard - entity framework kept throwing very strange exception. Sometimes it worked - no exception but sometimes it did not. First I was trying to fix the problems one by one but when I got another one I realized that my general approach is probably wrong.

So that is the general practice to implement for implementing persistence in ASP.NET MVC application ? Do I just call saveChanges after each change ? Isn't that little inefficient ? And I don't know how to do that with Services patter anyway (services work with entities so I'd have to pass context instance to them so that they could save changes if they make some).

Some links to study materials or tutorials are also appreciated.


Note: this question asks for programing practice. I ask those who will consider it vague to bear in mind that it is still solving my very particular problem and right technique will save me a lot of technical problems before voting to close.

Rasto
  • 17,000
  • 40
  • 141
  • 232
  • 2
    By reading your description I have bad feeling that you are using single shared instance of the context and just call `SaveChanges` on that instance during end request in http module. – Ladislav Mrnka Mar 22 '11 at 22:48
  • @Ladislav Mrnka your bad feeling is right but now I'm rebuilding this to use repository pattern. Just need to figure few things about how to use that pattern correctly. – Rasto Mar 23 '11 at 04:40
  • 2
    Here you have description why your current solution didn't work: http://stackoverflow.com/questions/3653009/entity-framework-and-connection-pooling/3653392#3653392 – Ladislav Mrnka Mar 23 '11 at 05:46
  • @Ladislav Mrnka I don't think that is the reason. I'm well aware of "EF loading single each entity only once per context". But in my case there is only my application connected to the database. So there is no risk that data would change externally so I'd be working with not actual entities when I'm using single static context for entire application. Not trying to say that it's a good pattern. – Rasto Mar 23 '11 at 06:18
  • 1
    That description has two parts. You described the first - identity map. The bigger problem can be shared unit of work where save changes can save incomplete updates from concurrent requests processing. – Ladislav Mrnka Mar 23 '11 at 07:02
  • @Ladislav Mrnka that might have been my problem. Thank you. I'm going to ask more questions about Entity framework, repository pattern and use of repository in service layer (it should not be used in controllers directly right ? Without service layer intermediation) before I decide how to rebuild my application. I already have one mode on the topic (feel free to check my profile). Btw. I wanted what's SO's language policy? Could I response to your comments in Czech or Slovak (not that I'm going to anyway)? – Rasto Mar 23 '11 at 07:21
  • @drasto: No, SO has strict English policy. This is not discussion but Q/A site and everybody should be able to react on your posts. Before you ask questions about repositories I recommend you using search and check already asked questions: http://stackoverflow.com/questions/tagged/repository-pattern+entity-framework – Ladislav Mrnka Mar 23 '11 at 08:00
  • @Ladislav Mrnka Well the fact that it is Q/A site and everybody should be able to answer does not necessarily imply strict English policy... Some people are not going to be able to ask and respond just because of that policy. But I got the point - majority of programmers speak English so other language will just cause some people to not to understand. I have checked the search and still I asked one more question about the topic http://stackoverflow.com/questions/5410381/generate-poco-classes-from-model-using-t4-templates-vs-ef4-1-simplified-api-mode. Please feel free to post some answer :). – Rasto Mar 23 '11 at 19:25

3 Answers3

2

It's going to be no more or less efficient than calling a stored procedure that many number of times (with respect to number of connections that need to be made).

Nominally, you would make all your changes to the object set, then SaveChanges to commit all those changes.

So instead of doing this:

mySet.Objects.Add(someObject);
mySet.SaveChanges();
mySet.OtherObjects.Add(someOtherObject);
mySet.SaveChanges();

You just need to do:

mySet.Objects.Add(someObject);
mySet.OtherObjects.Add(someOtherObject);
mySet.SaveChanges();
// Commits Both Changes
Tejs
  • 38,896
  • 8
  • 64
  • 81
2

You just need to make sure SaveChanges gets called before your request finishes. At the bottom of a controller action is an ideal place. My controller actions typically look like this:

public ActionResult SomeAction(...) 
{
    _repository.DoSomething();
    ...
    _repository.DoSomethingElse();
    ...
    _repository.SaveChanges();
    return View(...);
}

This has the added benefit that if an exception gets thrown, then SaveChanges will not get called. And you can either handle the exception in the action or in Controller.OnException.

Matt Greer
  • 57,161
  • 16
  • 118
  • 122
  • What about putting that repository save changes into Global action filter so it gets called `automatically` without having to write it manually at the and of every action? Would that have any disadvantages ? – Rasto Mar 22 '11 at 19:15
  • 1
    The problem with that is what if (in my example) `DoSomething()` finishes and adds a valid change to the repository. But then `DoSomethingElse()` fails, and so at this point I no longer want to save any changes? If you automatically called SaveChanges after all requests no matter what, it could lead to corrupt data. Basically the pattern above is a poor man's transaction. It would be even better to really run all of these things in a real transaction. – Matt Greer Mar 22 '11 at 19:18
  • @Matt Greer isn't there some way to check if there was exception during action execution from action filter ? That would solve problem you are addressing and it would be still 'automatic'... – Rasto Mar 22 '11 at 19:29
  • @drasto - I'm sure there is. If you really want to automatically call SaveChanges you could probably devise something that would work. Something like set a flag in `Controller.OnException` and if that flag is set don't call SaveChanges. IMO it'd be more work than it was worth. But then again, I'm also generally not a fan of "magic" like that happening, I like to keep explicit control for the most part. – Matt Greer Mar 22 '11 at 19:52
  • @Matt Greer I'm fan of any magic that lets me forget about persistence... Otherwise I want to have everything explicit as well. I'm watching some tutorial right now on repositories and I'd like to ask: When you create your repository methods do they return `IEnumrable` or `IQueryable`? I would say that when you use Entity framwork `IEnumerable` makes more sense. – Rasto Mar 22 '11 at 20:35
  • 1
    For me I return `IEnumerable` as I don't think the controller should be massaging data. It should ask the repo a question, get an answer, and just pass the answer on to the correct view. The controller shouldn't know or care whether the data the repo just gave it is in memory or still in the database. But that's just my opinion, other people like to return `IQueryable` and let the controller filter/change/whatever the data before the actual db query takes place. – Matt Greer Mar 22 '11 at 20:40
1

Usually your data access is wrapped by an object implementing the repsitory pattern. You then invoke a Save() method on the repository.

Something like

var customer = customerRepository.Get(id);
customer.FirstName = firstName;
customer.LastName = lastName;
customerRepository.SaveChanges();

The repository can then be wrapped by a service layer to provide view model objects or DTO's

Isn't that little inefficient ?

Don't prematurely optimise. When you have a performance issue, analyse the performance, identify a cause and then optimise. Repeat.

Update

A repository wraps data access, usually a single entity. A service layer wraps business logic and can access multiply entities through multiple repositories. It usually deals with 'slim' models or DTO's.

An example could be something like getting a list of invoices for a customer

public Customer GetCustomerWithInvoices(int id) {

  var customer = customerRepository.Get(id);
  var invoiceList = invoiceRepository.GetAllInvoicesFor(id);

  return new Customer {
    Customer = customer,
    Invoices = invoiceList
  };

}
David Glenn
  • 23,572
  • 17
  • 70
  • 94