MVC, ORM, and data access patterns

I think I got into a state of "paralysis by analysis." I have an MVC application using EF as an ORM. So Iโ€™m trying to decide on the best data access pattern, and so far I think that all the data access logic in the controllers is the way to go ... but this does not seem to be true. Another option is to create an external repository that handles data interaction. Here are my pros / cons:

If I embed access to these controllers, I get the code as follows:

using (DbContext db = new DbContext()) { User user = db.Users.Where(x=>x.Name == "Bob").Single(); user.Address.Street = "some st"; db.SaveChanges(); } 

Thus, I get the full benefits of lazy loading, I close the connection immediately after I finish, I am flexible about where the proposal is all the subtleties. Con - I mix a bunch of things in one method - checking data, accessing data, interacting with the user interface.

With the repository, I will open access to the data, and theoretically I can simply replace the repositories if I decide to use ado.net or switch from another database. But I donโ€™t see a good clean way to implement lazy loading and how to manage DbContext / connection lifetime. Let's say I have an IRepository interface with CRUD methods, how would I load a list of addresses belonging to this user? Creating methods like GetAddressListByUserId looks ugly, wrong, and will force me to create a bunch of methods that are just as ugly, and it makes little sense when using ORM.

I am sure that this problem has been solved like a million times, and I hope that there will be a solution somewhere.


And another question about the repository template - how do you feel about objects that are properties? For example. The user has a list of addresses, how would you retrieve this list? Create repository for address? With ORM, the address object does not need to refer to the user, and not to the Id field, with the repo - it will have to have it all. More code, more open properties.

+8
c # design-patterns asp.net-mvc orm asp.net-mvc-3
source share
3 answers

The approach you choose depends on the type of project you are going to work with. For small projects that require the Rapid Application Development ( RAD ) approach, it can be almost normal to use your EF model directly in the MVC project and have access to the data in the controllers, but the larger the project, the more dirty it will become, and you will start to face more and more new problems. If you need good design and maintainability, there are several different approaches, but in general you can stick to the following:

Keep your controllers and views clean. Controllers should control the flow of applications, and not contain access to data or even business logic. Views should be used only for presentation - provide it with a ViewModel and present it as Html (without business logic or calculations). A ViewModel for presentation is a pretty clean way to do this.

A typical controller action would look like this:

 public ActionResult UpdateCompany(CompanyViewModel model) { if (ModelState.IsValid) { Company company = SomeCompanyViewModelHelper. MapCompanyViewModelToDomainObject(model); companyService.UpdateCompany(company); return RedirectToRoute(/* Wherever you go after company is updated */); } // Return the same view with highlighted errors return View(model); } 

Due to the aforementioned reasons, itโ€™s good to abstract data access (testability, ease of switching the data provider or ORM, or something else, etc.). The Repository template is a good choice, but here you also get several implementation options. There has always been a lot of discussion about generic / non-generic repositories, whether IQueryable s should be returned, etc. But ultimately it's up to you to choose.

By the way, why do you want lazy loading? As a rule, you know exactly what data you need for a certain type, so why did you decide to retrieve it in a deferred way, thereby making additional database calls, instead of loading everything you need in one call? Personally, I believe that everything is in order to have several Get methods for retrieving objects with or without children. For example.

 public class CompanyRepository { Get(int Id); Get(string name); GetWithEmployees(int id); ... } 

This may seem a bit picky, and you can choose a different approach, but as long as you have a template that suits you, maintaining the code is much easier.

+7
source share

Personally, I do this:

I have an abstract domain level that has not only CRUD methods, but also specialized methods, for example UsersManager.Authenticate (), etc. Inside, it uses data access logic or an abstraction of the data access level (depending on the level of abstraction I need).

As a rule, it is better to have an abstract dependency. Here are some good points:

  • you can replace one implementation with another later.
  • You can unit test your controller if necessary.

Like the controller itself, let it have 2 constructors: one with an abstract domain access class (for example, a domain facade) and another (empty) constructor that selects the default implementation. Thus, your controller lives well during the execution of the web application (calling the empty constructor) and during unit testing (with the encapsulated domain word).

In addition, to be able to easily switch to another domain later, be sure to add the domain creator instead of the domain itself. Thus, by localizing the construction of the domain level for the domain creator, you can switch to another implementation at any time simply by restoring the domain creator (I mean some factory as the creator).

Hope this helps.

Adding

  • I would not recommend using CRUD methods at the domain level, because this will become a nightmare whenever you enrich the unit testing phase or even more, when you need to change the implementation to a new one at a later time.
+5
source share

It really comes down to where you want your code. If you need access to data for an object, you can put it behind an IRepository object or in a controller, it doesnโ€™t matter: you still end up with either a series of GetByXXX calls or an equivalent code. In any case, you can lazy the load and manage the lifetime of the connection. So now you need to ask yourself: where do I want my code to live?

Personally, I would say to get it out of the controller. By this I mean moving to another level. Perhaps using an IRespository type, where you have a series of GetByXXX calls. Of course they are ugly. Wrong? I would say otherwise. At least they are all contained in the same logical layer together, and are not scattered across all controllers, where they are mixed with the verification code, etc.

0
source share

All Articles