views:

561

answers:

2

I've been going through the tutorials (specifically ones using Linq-To-Entities) and I understand the basic concepts, however some things are giving me issues.

The tutorials usually involve only simple models and forms that only utilize basic create, update and delete statements. Mine are a little more complicated, and I'm not sure I'm going about this the right way because when it comes time to handle the relationships of a half dozen database objects, the tutorials stop helping.

For the post method, the usual way of performing CRUD operations

entities.AddToTableSet(myClass);
entities.SaveChanges();

Won't do what I want, because a fully implemented class isn't getting posted to the controller method. I may post individual fields, form collections, or multiple DTO objects and then call a method on a service or repository to take the information I receive from a form post, along with information that it needs to query for or create itself, and then from all of those things, create my database object that I can save.

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Add(int id, [Bind(Exclude = "Id")] ClassA classA,
                        [Bind(Exclude = "Id")]ClassB classB)
{
   // Validation occurs here

   if(!ModelState.IsValid)
      return View();

   try
   {
      _someRepositoryOrService.Add(id, classA, classB);
      return RedirectToAction("Index", new { id = id });
   }
   catch(Exception ex)
   {
      // Logging and exception handling occurs here
   }
}


public void Add(int id, ClassA classA, ClassB classB)
{
    EntityA eA = new EntityA
    {
        // Set a bunch of properties using the two classes and
        // whatever queries are needed
    };

    EntityB eB = new EntityB
    {
        // Set a bunch of properties using the two classes and
        // whatever queries are needed
    };

    _entity.AddToEntityASet(eA);
    _entity.AddToEntityBSet(eB);
    _entity.SaveChanges();
}

Am I handling this correctly or am I bastardizing the framework? I never actually use an entity object directly, whenever I query for one I put the information I need in a DTO and base my Views off of that. Same goes with the creation. Is this allowed, or is my avoidance of using entities directly going against the purpose of using the framework?

Edit: I'm also worried about this approach because it requires empty constructors to properly do the LINQ queries because of this error message:

Only parameterless constructors and initializers are supported in LINQ to Entities.

This isn't a big deal since I rarely need logic int the constructors, but is this an issue to have no constructors and only public properties?

+4  A: 

I would say using DTOs and wrapping the Entity Framework with your own data access methods and business layer is a great way to go. You may end up writing a lot of code, but it's a better architecture than pretending the Entity Framework generated code is your business layer.

These issues aren't really necessarily tied to ASP.NET MVC in any way. ASP.NET MVC gives basically no guidance on how to do your model / data access and most of the samples and tutorials for ASP.NET MVC are not production worthy model implementations, but really just minimal samples.

It seems like you are on the right track, keep going.

In the end, you are using Entity Framework mostly as a code generator that isn't generating very useful code and so you may want to look into other code generators or tools or frameworks that more closely match your requirements.

Michael Maddox
I'm really only using the Entity framework to try something new. I'm use to using nHibernate. Do you have any suggestions for a better generator or framework I should be using?
Brandon
I don't know of anything that's a great fit for your needs. Some of these are commercial and some are free. In no particular order: T4 Templates, CodeSmith, LLBLGen Pro.
Michael Maddox
This is mostly a very good answer (+1), but I disagree that he is using the Entity Framework as a code generator. What is far more important is that he is using the Entity Framework to map his database into object space. This is important even if you never actually materialize an entity type; you still use the mapping entities in your LINQ to Entities queries as you project them onto other types.
Craig Stuntz
I don't mean to imply that he shouldn't use Linq or shouldn't use an ORM. He should do both of those things to the extent that it makes sense. There are alternative solutions that provide Linq/ORM features that don't involved Entity Framework. LLBLGen Pro is a perfect example. LLBLGen Pro provides all of the above: Linq, ORM, and code generation. I could argue that the other two tools I mentioned can interoperate with ORMs and meet all three needs (better in this scenario, in my opinion, than Entity Framework) as well.
Michael Maddox
+3  A: 

_someRepositoryOrService.Add(id, classA, classB);

I would say you couple your repositories with presentation layer. This shouldn't be. Your repositories should only work with entities. Next, notice how your Add method

public void Add(int id, ClassA classA, ClassB classB)

breaks Separation of Concerns (SoC). It performs two tasks:

  1. map view data into entities
  2. save to repository

Obviously the first step should be done in presentation layer. Consider using model binders for this. It can also help you to solve the constructors problem, since your model binders can be made aware of the construction requirements.

Check also this excellent post by Jimmy Bogard (co-author of ASP.NET MVC In Action) about ViewModels. This might help you to automate mapping. It also suggest a reversed technique - make your controllers work with entities, not ViewModels! Custom action filters and model binders are really the key to eliminate routine that that don't really belong to controllers but rather an infrastructure detail between view and controller. For example, here's how I automate entities retrival. Here's how I see what controllers should do.

The goal here is to make controllers contentrate on managing business logic, putting aside all the technical details that do not belong to your business. It's techical constraints that you talk about in this question, and you let them leak into your code. But you can use MVC tools to move the to them infrastructure level.

UPDATE: No, repositories shouldn't handle form data, that's what I mean by "coupling with presentation". Yes, repositories are in the controller, but they don't work with form data. You can (not that you should) make form work with "repositories data" - i.e. entities - and that's what most examples do, e.g. NerdDinner - but not the other way. This is because of the general rule of thumb - higher layers can be coupled with lower ones (presentation coupled with repositories and entities), but never low level should be coupled to higher ones (entities depend on repositories, repositories depend on form model, etc).

The first step should be done in the repository, that's right - except that mapping from ClassX to EntityX does not belong to that step. It's mapping concern - an infrastructure. See for example this question about mapping, but generally if you have two layers (UI and repositories) they shouldn't care about mapping - a mapper service/helper should. Beside Jimmy's blog, you can also read ASP.NET MVC In Action or simply look at their CodeCampServer for how they do mapping with IEntityMapper interfaces passed to controller constructors (note that this is more manual and less-work approach that Jimmy Bogard's AutoMapper).

One more thing. Read about Domain Driven Design, look for articles, learn from them, but you don't have to follow everything. These are guidelines, not strict solutions. See if your project can handle that, see if you can handle that, and so on. Try to apply this techniques since they're generally the excellent and approved ways of doing development, but don't take them blindly - it's better to learn along the way than to apply something you don't understand.

queen3
For coupling the repositories, I'm not sure what you mean, having a repository in the controller seems to be what most of the tutorials do as well. As for the first step being done in the presentation layer, shouldn't it be done in the repository? I thought the purpose of repositories was to worry about handling the form data to database conversion?
Brandon
Also thank you for the examples and advice. I haven't had time to actually make the changes, but it's a nice nudge in the right direction.
Brandon
See update. I would suggest to refactor slowly, for example first do _realEntityRepository.Add(EntityMapper.From(classA)); (or classA.MapToEntity()), then involve custom ModelBinder (which is a big topic), then add IoC container (another big topic), and so on.
queen3