Rebuilding imar.spaanjaars.com in ASP.NET MVC 2 - Part 4 - Repositories, Testability and Inversion of Control

UPDATE: Links to the MVC site on the URL mvc.spaanjaars.com are no longer active, now that the site is live at imar.spaanjaars.com.

I just uploaded a new version of my web site in MVC to mvc.spaanjaars.com. This new version has the following features:

  • All data access is now done with repositories (using Entity Framework at run-time).
  • My Controllers and repositories are fully testable.
  • I am using Castle Windsor as my Dependency Injection tool to inject concrete repositories into my controllers at run-time or during testing.

Some of the main USPs of the MVC framework are separation of concerns and testability. So when rebuilding my web site in MVC, I kept these principles in mind. One area where that is really useful is in the data access part of the application. Rather than tying my controllers to the database or data access layer directly, I am injecting interfaces for data access into my controllers at run time. These interfaces in turn provide access to repository interfaces. I then have a bunch of concrete classes that provide real data at run-time, and test data during testing. I'll show you some of the code for the repositories first, followed by a discussion on using Castle Windsor for the dependency injection. The second half of the article shows you how to use extension methods to create behavior that is shared between real and fake implementations of your repository classes.

Using Repositories

NOTE: at the end of the article you can download a full, working example of the concepts presented in this article. You should realize that the sample application is just that: a sample. In a real-world application you need a lot more than what is presented in this article. Additionally, the code does not necessarily show best practices for MVC applications as it's focus is on an implementation of the Repository pattern using extension methods. The database for the sample application contains a bunch of fake categories and articles. If they don't look like true categories and content articles you may find on a web site like mine, but think they look more like products: that's because I generated the records automatically using Red Gate's Data Generator as explained here. Also note: the application is using MVC 2 and Entity Framework 4; as such you need Visual Studio 2010 to compile and run it. You probably could downgrade the code and recreate the model in VS 2008, but I haven't tried that yet.

One of the ideas behind the Repository pattern is to have a repository for each aggregate root in your model. You'll find a great explanation of the pattern and concrete examples in this article in the NHibernate FAQ. One of the ideas presented in that article is to have a generic IRepository interface that could look like this:

public interface IRepository<T>
{
  T GetById(int id);
  void Add(T entity);
  void Remove(T entity);
}

You can then use this interface for a concrete implementation on, say, a Product like this:

public class ProductRepository : IRepository<Product>
{
  public Product GetById(int id)
  {
    // Implementation here
  }
  public void Add(Product entity)
  {
    // Implementation here
  }
  public void Remove(Product entity)
  {
    // Implementation here
  }
}

This works excellent, and enables you to do something like this in your code:

ProductRepository myProductRepository = new ProductRepository();
Product myProduct = myProductRepository.GetById(23);

What I personally find difficult about this "repository per aggregate root" concept is the fact that in your application, things are not always as disconnected as each aggregate root seems to indicate. Sometimes you do need a Customer from the CustomerRepository and associate it with an Order from an OrderRepository. This isn't a big deal when dealing with, say, test data in fake repositories or when working with your own data access classes, but it does become problematic with Entity Framework or other ORM frameworks that need to keep track of these entities from the same underlying mechanism. If you try to associate an entity from one EF context with another entity from another context you get an error such as the following:

The relationship between the two objects cannot be defined because they are 
attached to different ObjectContext objects.

So you need to find a way to share the ObjectContext from EF and still separate your aggregate roots. To solve this problem for the MVC version of my web site, I am using an IRepositoryWrapper interface whose concrete implementations can hold an instance of a single ObjectContext and provides access to a number of Repositories that get a reference to this ObjectContext. To show you how this works, I created a simple web application using ASP.NET MVC. The application is an extremely simple web site that shows articles in specific categories. Figure 1 shows the database model for the application.

Data Model of the Sample Application
Figure 1

The application has an MVC View that displays a list of categories. Once you click a category you get a new View that displays all articles for that category. In the remainder of this article I'll show you the underlying model and design.

First, take a look at a part of the (simplified) class diagram of my application, shown in Figure 2.

Class Diagram with IGenericRepository and the IRepositoryWrapper
Figure 2

I'll get to the IRepositoryWrapper later, but for now focus on the two interfaces on the left. IGenericRepository<T> is a variation of the interface you saw earlier and defines the base services a concrete implementation needs to supply: All, Add and Remove. For simple aggregate roots, like Category, this is more than enough. As an example, I also added IArticleRepository that inherits IGenericRepository<Article> and adds one extra method: PurgeDeletedItems that deletes items marked for deletion from the database. This just serves as an example. You could, and probably should, implement PurgeDeletedItems as an extension method as explained later in this article.

Inside my Model class library, there are two concrete repositories: ArticleRepository and CategoryRepository:

Concrete Repository Classes
Figure 3

You can see that each of these concrete classes implements the members defined by the interfaces they inherit. Additionally, you can see they have a field called _entities which is of type MvcDemoEntities, the Entity Framework ObjectContext instance used in my application. The concrete implementation uses these entities for data access. For example, Remove in the ArticleRepository looks like this:

public void Remove(Article item)
{
  Article article = _entities.Articles.Where(c => c.Id == item.Id).FirstOrDefault();
if (article != null)
{
article.Deleted = true;
}
}

The concrete repositories don't create this instance themselves; instead, they get a reference to the ObjectContext passed to them in their constructor like this:

public ArticleRepository(MvcDemoEntities entities)
{
  _entities = entities;
}

So who instantiates the ObjectContext? The concrete implementation of IRepositoryWrapper does. Take another look at Figure 2 and notice how the IRepositoryWrapper has two properties: Articles and Categories, of type IArticleRepository and IGenericRepository<Category> respectively. The concrete implementation of this class looks like this:

public class RepositoryWrapper : IRepositoryWrapper
{
  MvcDemoEntities _entities = new MvcDemoEntities();
  private CategoryRepository _categories;
  private ArticleRepository _articles;

  public IGenericRepository<Category> Categories
  {
    get
    {
      if (_categories == null)
      {
        _categories = new CategoryRepository(_entities);
      }
      return _categories;
    }
  }
  
  public IArticleRepository Articles
  {
    get
    {
      if (_articles == null)
      {
        _articles = new ArticleRepository(_entities);
      }
      return _articles;
    }
  }
  
  public int SaveChanges()
  {
    return _entities.SaveChanges();
  }
}

The two properties are lazy loaded and instantiate a repository when requested and pass it the _entities ObjectContext. This in turn means the repositories all share the same ObjectContext enabling you to share entities across repositories. With this setup, you can now do stuff like this in a Controller method:

RepositoryWrapper _repositoryWrapper = new RepositoryWrapper();
IEnumerable<Article> allArticles = _repositoryWrapper.Articles.All;
return View(activeArticles);	    

Likewise, you can access _repositoryWrapper.Categories to get access to the categories in the system.

This is all fine, but doesn't really promote testability of your repositories. Also, since the Controller is instantiating the RepositoryWrapper directly, it's not easy to swap the RepositoryWrapper for another implementation. Finally, it's now pretty difficult to test your Controllers as they are tied to the concrete RepositoryWrapper that in turn uses the Entity Framework and a live database for all data access. Fortunately, the code I've shown you lays out a nice foundation to improve on, using Castle Windsor, a few Fake classes and a whole bunch of extensions methods.

Testing Your Application

The first step in making your Controllers testable is by removing the dependency on the repositories; in particular the dependency on the RepositoryWrapper. This can easily be fixed in a few steps:

  • Download, unzip and reference Castle Windsor in your web and test project.
  • Add configuration information to the config files to tell Windsor which class to instantiate for which interface. For example, in Web.config for my MVC application I have this:
    <castle>
      <components>
        <component id="RepositoryWrapper" 
          service="MvcDemo.Model.IRepositoryWrapper, MvcDemo.Model" 
          type="MvcDemo.Model.RepositoryWrapper, MvcDemo.Model" 
          lifestyle="transient"
        />
      </components>
    </castle>            

    Likewise, in app.config of my Test project I have this:

    <castle>
      <components>
        <component
          id="RepositoryWrapper"
          service="MvcDemo.Model.IRepositoryWrapper, MvcDemo.Model"
          type="MvcDemo.Model.FakeRepositoryWrapper, MvcDemo.Tests"
          lifestyle="transient" />
      </components>
    </castle>            

    In other words, I want Castle Windsor to instantiate a concrete RepositoryWrapper in my MVC application, and an instance of FakeRepositoryWrapper in my test project whenever an instance of IRepositoryWrapper is required.

  • To tell your MVC application to instantiate controllers through Windsor you need to add the following class to your project:

    public class WindsorControllerFactory : DefaultControllerFactory
    {
    WindsorContainer container; public WindsorControllerFactory() { container = new WindsorContainer(new XmlInterpreter( new ConfigResource("castle"))); var controlerTypes = from t in Assembly.GetExecutingAssembly().GetTypes() where typeof(IController).IsAssignableFrom(t) select t; foreach (Type t in controlerTypes) { container.AddComponentLifeStyle(t.FullName, t, LifestyleType.Transient); } } protected override IController GetControllerInstance( RequestContext requestContext, Type controllerType) { if (controllerType == null) { return null; } else { return (IController)container.Resolve(controllerType); } } }
    This code uses Windsor to create the controllers, which then passes a concrete instance of the IRepositoryWrapper class in the constructor of the controller, based on the Windsor configuration information.

  • To tell the MVC framework you want to use a different ControllerFactory, you need to add the following code to Application_Start in the Global.asax file:

    ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory());
    Finally, you need to modify the constructors of your controllers so they accept an instance of IRepositoryWrapper:

    IRepositoryWrapper _repositoryWrapper;
    
    public ArticlesController(IRepositoryWrapper repositoryWrapper)
    {
      _repositoryWrapper = repositoryWrapper;
    }        

    This effectively removes the dependency between the controller and the concrete RepositoryWrapper you saw in an earlier code example. Instead, the controller now accepts anything that implements IRepositoryWrapper. The code in the Controller method can now be simplified to:

    IEnumerable<Article> allArticles = _repositoryWrapper.Articles.All;
    return View(activeArticles);	    

While this seems like a lot of work, it opens up a number of interesting possibilities. For example, you can now test your Controllers by doing the following:

  1. Create concrete fake classes of IRepositoryWrapper, IGenericWrapper<Category> and IArticleRepository that are specific to testing.
  2. Implement the relevant members in these classes. For example, the All property in FakeArticleRepository looks like this:

    public IQueryable<Article> All
    {
    get
    {
    return _tempList.AsQueryable();
    }
    }
    The _tempList variable holds a reference to a List<Article> that has been instantiated in the Fake class's constructor:

    public FakeArticleRepository()
    {
    _tempList = new List<Article>();
    for (int i = 0; i < 100; i++)
    {
    Random myRandom = new Random();
    _tempList.Add(new Article()
    {
    Id = i,
    CategoryId = myRandom.Next(4),
    Summary = "Summary " + i.ToString(),
    Deleted = i % 2 == 0,
    Body = "Body " + i.ToString(),
    CreateDateTime = DateTime.Now,
    UpdateDateTime = DateTime.Now
    });
    }
    }
    This gives me a bunch of fake articles to work with in my test application. I randomly assign a category between 1 and 4 and set some articles to be deleted and some as active. This setup enables me to carry out a test of a Controller like this:

    using (ArticlesController articlesController = new ArticlesController(RepositoryWrapper))
    {
      var result = articlesController.List(1); // Get articles in category 1
      Assert.IsNotNull(result);
      var returnedItems = (result.ViewData.Model as IEnumerable<Article>).ToList();
      returnedItems.ForEach(a => Assert.IsFalse(a.Deleted));
      returnedItems.ForEach(a => Assert.IsTrue(a.CategoryId == 1));
    }
    The RepositoryWrapper instance is created in the test's base class and uses Windsor to create an instance of IRepositoryWrapper based on the application's config file: a FakeRepositoryWrapper in my case:

    public class BaseTestClass
    {
    protected IRepositoryWrapper RepositoryWrapper;
    public BaseTestClass()
    {
    using (IWindsorContainer container = new WindsorContainer(new XmlInterpreter(new ConfigResource("castle"))))
    {
    RepositoryWrapper = container.Resolve<IRepositoryWrapper>();
    }
    }
    }

Making Your Tests More Reliable

At this point you may be thinking: "Now wait a minute; isn't he just testing his fakes, and not his real repositories?" Yes, to some extent you would be right. For example, imagine my IGenericRepository<T> had a member called GetById(int id) that was implemented in the real and fake repositories as follows (note the faulty implementation of GetById in the real implementation):

// Fake implementation
public Article GetById(int id)
{
  return _tempList.Find(a => a.Id == id);
}

// Real implementation
public Article GetById(int id)
{
  return _entities.Articles.Where(a => a.Id > id).First();
}  

If this was real code, and I was testing against my FakeArticleRepository, I would never catch this bug. The Fake would return the correct article, but at run-time I would receive the first article with an ID higher than the one requested. To prevent these kind of issues where there is a mismatch between your fake and real implementations, I haven't added members like GetById or GetByCategoryId to the interfaces and real implementations. Instead, I have created a bunch of extension methods on the respective repository interfaces that do all the repository logic such as querying for me. Because both the real and the fake repositories implement this interface, they get access to these extension methods which in turn means they exhibit the exact same behavior when run. I pretty much dumbed down the repository interfaces to "a bunch of objects of type T" with the All property and let the extension methods do the hard work. I can trust a property such as All to be reliable across both implementations as it requires little to no code. But when it comes to querying or other logic, an error is easily made in one of the two concrete providers, so it's good to move te logic to a shared location that multiple concrete implementations can use. To see what I mean, consider these two methods in an Extensions class:

public static IQueryable<Article> GetActive(this IArticleRepository repository)
{
return repository.All.Where(c => !c.Deleted);
}
public static Article GetById(this IArticleRepository repository, int id)
{
return (from c in repository.GetActive()
where c.Id == id
select c).FirstOrDefault();
}

GetActive makes sure I am not returning items that have been marked as deleted. GetById in turn uses GetActive to get all non-deleted items and then queries the one with the ID requested. With the real implementation using EF, I get a composable query that executes a simple and clean SQL statement against the database. With the Fake implementation, I get the same, but instead of targeting a (slow) database, I query the in-memory representation of my fake list of articles. Either way, I am testing the implementation of GetById, without needing a real database at test time. This makes it pretty easy to test your repositories and your Controllers using fake objects and fake data, while still being able to true test runtime code.

Wrapping Up

Pfffeew, I covered a lot in a relatively short article. Let's briefly recap the main topics:

  • Using repositories is a good thing to create maintainable and testable applications.
  • While having a repository per aggregate root is a good thing too, when using an ORM such as EF you need a mechanism to share the ObjectContext between repositories.
  • By using a RepositoryWrapper you can achieve two main goals:
    • You can let multiple repositories share a single instance of the ObjectContext
    • You provide easy access to your various repositories. This means you can do stuff like MyRepositoryWrapper.Articles.GetById(23) and MyRepositoryWrapper.Categories.GetById(3) to get articles and categories. IntelliSense will help you find the right repository and help you find the right methods.
  • By embedding all your querying and other repository logic in the concrete implementation of your repository, you run the risk of introducing bugs you cannot test for. Since you're really testing the Fake implementation of your repository, bugs in the real repository may go unnoticed.
  • By moving much of your repository logic to extension methods you can easily reuse that behavior in both real and fake implementations, making tests more real and reliable.

I haven't covered each and every piece of code necessary to make these concepts work. However, the download that comes with this article has a fully working, and testable application that shows all major concepts. I haven't written a test for each possible scenario, but instead wrote just a few tests to demonstrate the main concepts.

Since this is a work in progress, I am looking forward to a discussion on this topic. Let me know what you think of this using the Comment feature at the end of this article.

References

Downloads


Where to Next?

Wonder where to go next? You can read existing comments below or you can post a comment yourself on this article .


Consider making a donation
Please consider making a donation using PayPal. Your donation helps me to pay the bills so I can keep running Imar.Spaanjaars.Com, providing fresh content as often as possible.



Feedback by Other Visitors of Imar.Spaanjaars.Com

On Saturday, April 03, 2010 11:56:39 AM Nick said:
Good stuff Imar
Thanks for sharing. I wonder what are the alternatives to EF? My understanding is it's not really a mature product which can be risky for a decent sized project.

Cheers
Nick
On Saturday, April 03, 2010 1:42:01 PM Imar Spaanjaars said:
Hi Nick,

There are many alternatives, including LINQ to SQL, NHibernate, custom design (http://imar.spaanjaars.com/QuickDocId.aspx?quickdoc=476) and many other ORM systems.

However, you may want to take another look at EF. In EF 4 (which is about to ship), many issues have been addressed, making EF a good option as well.

Cheers,

Imar
On Sunday, April 04, 2010 2:51:43 PM Nick said:
Hi Imar

I wonder what are the performance implications of using Castle Windsor?

All Castle Windsor does is just instantiate the correct implementation of the interface and passes it to the constructor of your controllers.

Let's say I go about it this way(controller flavour): IEnumerable[Category] activeCategories = new RepositoryWrapper().Categories.GetActive();

Or instantiate _repositoryWrapper in the constructor if you prefer(much cleaner too).

No mods to config files, no dependency on Castle, no reflection calls etc, yet fully testable.

Seems a like a pursuit of perfection gone over the limit. What are your thoughts?

Cheers
Nick

PS
Error 1 The name 'UrlParameter' does not exist in the current MvcDemo\Global.asax.cs 19 60 MvcDemo.Web
On Sunday, April 04, 2010 3:01:02 PM Imar Spaanjaars said:
Hi Nick,

The performance implications are, AFAIK, pretty low.

Yes, you could do what you described here, but you'd lose the ability to switch the implementation with configuration as you somewhere are hardcoding your "current" implementation. That makes it difficult to switch your unit tests from the test repository to a real repository for integration tests in, say, a Continuous Integration Server. It also makes it hard to complete swap the repository (say you're switching to NHibernate) without recompilation of the application.

>> All Castle Windsor does is just instantiate the correct implementation of the interface
Yes, but it does it very well. In my case, it's only resolving a single type with no parameters, but it can resolve complex hierarchies where the types that are instantiated need other types in their constructors or properties as well. Add to that the ability to resolve param configuration from external files, and I am sold on the concept of Ioc, DI and Castle Windsor. YMMV, of course.

>>  The name 'UrlParameter' does not exist in the current MvcDemo\Global.asax.cs
As I said in the article, this is an MVC 2 application. UrlParameter was added recently (http://haacked.com/archive/2010/02/12/asp-net-mvc-2-optional-url-parameters.aspx) so it looks like you're not using the RTM version.

Cheers,

Imar
On Thursday, April 15, 2010 11:05:20 PM Randalo said:
This has nothing to do with this blog article, but what would you say is the difficulty level for PHP, and the difficulty level for Asp.Net?
For example:Would a high schooler be able to learn those languages, or do you need to be a college student, or even beyond that?
Is there certain curriculum you need to know?
Stuff like that
On Friday, April 16, 2010 9:20:38 AM Imar Spaanjaars said:
Hi Randalo,

ASP.NET may be harder to learn at first because it requires at least a bit of understanding of Object Oriented programming. However, depending on how complex the things are you're building, that may also be true for PHP.
In theory, a high schooler should definitely be able to learn and use ASP.NET. However, it depends on the person. I have seen high schoolers that understood it in days, and others that will never get it.

Cheers,

Imar
On Sunday, April 25, 2010 9:41:17 PM Randalo said:
Ok thanks so much for your help!
On Tuesday, April 27, 2010 5:30:22 PM Mr. D said:
Hi Imar,

Nice post. I have a question on nested tree view. Such as Category and Article on the same view. Do you have any idea how can I implement that?

Dusshyi
On Tuesday, April 27, 2010 7:21:26 PM Imar Spaanjaars said:
Hi there,

How is this related to repositories?

I am also not sure what you mean with nested trees. Isn't that just a mattter of multiple levels of branches?

Maybe you're better off posting that question on a forum such as this one: http://p2p.wrox.com/index.php?referrerid=385

Cheers,

Imar
On Tuesday, April 27, 2010 8:23:20 PM Mr. D said:
Hi Imar,

This might not related to this post, but my question is how do you retrieve Category and Article in one view.
Eg:
Category 1:
   Article 1
   Article 2
Category 2:
   Article 3
Category 3:
  Article 4

Dusshyi
On Wednesday, April 28, 2010 6:09:54 AM Imar Spaanjaars said:
If it's not related then please take this question to a place where it *is* related, such as the forum I suggested earlier.

Short version of my answer (and the last here): you can have a collection of Categories in your View where each Category exposes a collection of Articles that you can loop over.

Cheers,

Imar
On Thursday, May 06, 2010 12:09:58 PM Kurt Schroeder said:
Good Stuff!!!
On Sunday, May 09, 2010 1:45:03 PM Mr. D said:
Hi, Could you explain why you create Extentions instead of use the interface?

Dusshyi
On Sunday, May 09, 2010 1:55:19 PM Imar Spaanjaars said:
Hi there,

That is exactly what I am explaining in this article, so you may want to read it again. By creating extensions, I can resue them in both the real and in the fake implementations without implementing them twice (and running the risk of a mismatch between real and fake).

Cheers,

Imar
On Tuesday, May 25, 2010 2:51:23 PM kurt schroeder said:
This will be my "The answer is obvious" question for the day. I'm getting a configuration error, but i'm not sure which configuration is missing or inaccurate. In Nhibernate I've needed to compile the the config and the XML mappings as an embeded resource/ copy always. I triued this on the model, but it did not work, so the obvious is else where.
System.Configuration.ConfigurationErrors
    CategoryRepositoryTests (2 tests), 2 tests failed
      GetActive_returns_active_items_only, Failed: Unable to create instance of class MvcDemo.Tests.CategoryRepositoryTests. Error:
On Tuesday, May 25, 2010 3:17:56 PM Imar Spaanjaars said:
Hi kurt,

That's pretty difficult to say without seeing the actual error, and without knowing where and how you get this error. I can't even see how NHibernate is related to this, and how you're running these tests or trying to instantiate the class, so I am not sure why you think I can fix it for you ;-)

My advice: post this on the Wrox forum: http://p2p.wrox.com/index.php?referrerid=385 and provides lots of detail, including your test config file. If you think this is related to the project that comes with this article, send me an e-mail with, again, lots more detail.

Cheers,

Imar
On Tuesday, May 25, 2010 4:27:16 PM kurt schroeder said:
Hi Thanks for getting back to me quickly.
i downloaded the project,  added Castle.Windsor, compiled it, and attempted to run the unit tests. No configuration changes were made. I thought the fake repositories would make this not a problem.

I did not mean to cloud the issue with the NH references. There are some quirky things with NH and versions of Castle,  and every thing else with a version. As well as compiler options for the xml.
Is there a version of Castle that i should specificly be using.?
All projects are 4.0, but Castle is compiled to 3.5. I would not think this would be a problem.

Again thank you for the article serise and your help
I did not notice any place where i had to make changes except for the database.

KES

On Tuesday, May 25, 2010 6:19:09 PM Imar Spaanjaars said:
Hi kurt,

Ah, I see now. Looks like I forgot to include these files as they were added as a reference with "copy local" set to false.

Two ways to fix this:

1. Download the source that comes with this article as I just updated it.

2. Download Castle Winsor 2.1 from here: http://www.castleproject.org/castle/download.html. Unzip, and then add a *reference path* to the Project Properties of the Test Project to the folder Castle-Windsor-2.1.1\Castle-Windsor-2.1.1\bin\net-3.5.

Then compile and the tests should run.

Hope this helps,

Cheers,

Imar
On Tuesday, May 25, 2010 8:15:52 PM kurt Schroeder said:
I am able to get unit tests to function with NUnit. I am still not able to get test to run even with the changes you made and your instructions.  I really doubt Microsoft Test is causing the problem so this remains a mystery, but I have to conclude I’m doing something odd here. At one point I was ready to say it was because I use virtual machines for development. Well, I have it working with NUnit  so this is OK for me.
Your help is appreciated.
Thanks!
KES
On Tuesday, May 25, 2010 8:46:27 PM Imar Spaanjaars said:
Hi kurt,

Odd that it doesn't work. It works fine for me, even on a clean VS 2010 machine wihout Castle locally.

Anyway, glad it at least works with NUnit....

Cheers,

Imar
On Wednesday, May 26, 2010 1:44:02 PM Kurt Schroeder said:
I just seem to have a gift. Now I have to do the impossible (for me), stop trying to solve the mystery and get something accomplished.
Thanks you my friend
KES
On Friday, June 11, 2010 1:33:38 PM Nick said:
Hi Imar,

This is the best example on the web of how to set up Castle Windsor with MVC 2.

Seriously.

Thanks a lot mate.
On Wednesday, November 17, 2010 5:11:22 PM Kurt Schroeder said:
I've been having trouble finding a happy medium for Entity and SQL.
I'm do all access to entities in my service layer  a septate layer i still do not have a name for and not use the controllers for such things.
The problem is using Linq to Entity: i'm an all or nothing. I use complex types in entity and such, but try doing multilevel group by. I can do it, but the complexity that results with grouping by and using mapped entities  can make inline sql look good by comparison. so for now i'm back to views and stored procedures to do the heavy lifting concerning group by's. I curious as to how you are dealing with say a catalog and its associated that have mappings to categories, subcategories products where main categories are unique, but a sub category can be attached to one or all main cat's and the products can be attached to the Maim Cat, and to sub cats. To be sure the products are unique to their respective parent.

OK maybe too big a question, but i figure you'll have a link or two you can give me. thanks KES
On Wednesday, November 17, 2010 5:40:01 PM Imar Spaanjaars said:
Hi Kurt,

Sorry, no links on that topic....

Imar
On Monday, November 22, 2010 10:22:39 PM kurt schroeder said:
That's ok. I'm getting to the point where i'm starting to strikeout in not yet covered area. I've had to play catch up and i'm almost up with the pack. No small thanks to you.
On Thursday, December 02, 2010 8:34:47 PM Ross McLoughlin said:
Hi Imar,

Firstly, nice article. I'd be interested to hear how you pass data between the layers. In the example above it appears that your View depends on an Entity passed to it from the Data layer, effectively tying you presentation layer to the data access layer, and thereby violating the principle of loose coupling.

Today, I was trying to do something that should have been very simple. I wanted to display a list of categories in a drop down list in an MVC2 app. I have EF4 wired up, and being the good coder that I am, I have divided my app into 3 layers: presentation, domain logic, and data access layer. To get my list of of categories to the view I created a Data Transfer Object (DTO) in the DAL to hold the results of the LINQ query to get a list of categories. This is the returned to my Domain layer. In my domain later I map this to a local DTO using AutoMapper, and it is this DTO list of categories that is passed by to my Controller and then the view.

This all seems like a lot of hard work :-) In my example it took 2 transformations to get the list of categories back to the View, ie the Category entity is converted to a DTO in the DAL, and the converted again in the Domain layer.

Is there a better way of doing this? I feel that littering my code with lots of DTOs will adversely affect the maintainabily of my code down the line.

Regards, and thanks in advance

Ross

On Tuesday, December 07, 2010 8:51:24 AM Imar Spaanjaars said:
Hi Ross,

What you could is create a separate class library for your View Model, reference that from both projects and place the DTOs in that project. That way you have a common DTO definition.

Cheers,

Imar
On Tuesday, December 07, 2010 11:57:40 PM Ross said:
Heya,

That makes perfect sense.  I will try that tomorrow.

Thanks again,

Ross
On Sunday, January 16, 2011 2:55:25 PM Suman said:
Hi Imar,

Great article. Thanks a lot. I was reading the ASP .NET MVC 2 book from Apress and in that the author used the Linq to SQL and I was looking for samples using MVC using with EF4.

But I have some questions about EF4. How does EF4 handle the distribution of layers. Say if I have installed the web server in the DMZ and no database connectivity is allowed from that server, Is there a way that I can make use of EF4 without using a WCF service on an App Server?

I have been using Rockford Lhotkas CSLA for quite some and the distribution(switching from 2 tier to 3 tier) is quite simple with just a configuration change. Is there any features in EF4 for addressing this ?

Regards
Suman
On Sunday, January 16, 2011 3:03:25 PM Imar Spaanjaars said:
Hi Suman,

AFAIK, no, that's not possible. You need access to a database or use a service layer to make this work.

Cheers,

Imar
On Thursday, January 27, 2011 9:39:04 AM Steven said:
Hi Imar,

Thanks for you great article. I implemented some of the code in my own project. However, in every article about Repository Patterns and Unit of Work there's no example how to use it with a service layer.

For example:

You want to save an article in the save Action from the article controller. In the article controller you get the instance of an article through the articlerepository. You pass this instance to the service layer where the instance will be validation with custom validation and then saved. You cannot create a new Repository Wrapper in the service layer because the passed instance of article is hooked to another to another datacontext.

Do you have any idea how to use this with a service layer? Especially how to share your, in this case, repositorywrapper?
On Friday, January 28, 2011 9:55:42 AM Imar Spaanjaars said:
Hi Steven,

Here's what you could do:

1. Use DI to inject a Service class into your controller.

2. The Service could have methods to add, create, delete etc objects

3. Use DI to inject a UnitOfWork and a Repository into your service class.

4. Save the changes in the Service class by calling Commit on the UnitOfWork.

In my example, the wrapper serves more or less as a UnitOfWork.

Cheers,

Imar
On Friday, January 28, 2011 1:16:09 PM Steven said:
Hi Imar,

Thanks for your comment. That's exactly the same solution I implemented in my application. There is only one problem with the context. Each time the Repositorywrapper/Unit of Work is injected, a new datacontext is created. So if you use an object from the injected Repositorywrapper in the controller, and pass it to the service (where another repositorywrapper is injected) where you do an update of the object, you'll get an error because the object is attached to the context created in the controller.

I'm using Ninject for DI.

------------------------------------------------

Het is een beetje lastig om het in het Engels uit te leggen. Wat ik bedoel is dat bij het gebruik van jouw Repositorywrapper, er elke keer een nieuwe datacontext wordt aangemaakt zodra er een nieuwe Repositorywrapper wordt aangemaakt. Dus wanneer de wrapper wordt geinjecteerd in zowel de controller als de service, wordt er bij mij een nieuwe context aangemaakt. Deel je objecten tussen de controller en de service, bij het updaten van een object bijvoorbeeld, dan krijg ik een error omdat het object nog gekoppeld is aan de context die in de controller is geïnjecteerd.

Ik heb al veel voorbeelden gezien dan DI en repository patterns, maar nooit wordt er gebruik gemaakt van een service als tussenlaag. In principe moet je dus je Repositorywrapper delen tussen je controller en je service. Mijn DI (Ninject) maakt steeds een nieuwe instantie aan.

Ik begrijp dat dit verhaal misschien buiten de scope van jou artikel valt ;-)

On Friday, January 28, 2011 3:05:00 PM Imar Spaanjaars said:
Hi Steven,

You could store the current DataContext in the HttpContext.Current.Items collection so it's available throughout the entire request. This means you can use it from both the repositories as well as from the unit of work. You could wrap up the creation of the context in some code that checks for the presence of HttpContext.Current. if it's available, it stores the context in HttpContext.Current.Items; otherwise it could store it elsewhere, such as a static collection associated with the current thread.

Cheers,

Imar

Talk Back! Comment on Imar.Spaanjaars.Com

I am interested in what you have to say about this article. Feel free to post any comments, remarks or questions you may have about this article. The Talk Back feature is not meant for technical questions that are not directly related to this article. So, a post like "Hey, can you tell me how I can upload files to a MySQL database in PHP?" is likely to be removed. Also spam and unrealistic job offers will be deleted immediately.

When you post a comment, you have to provide your name and the comment. Your e-mail address is optional and you only need to provide it if you want me to contact you. It will not be displayed along with your comment. I got sick and tired of the comment spam I was receiving, so I have protected this page with a simple calculation exercise. This means that if you want to leave a comment, you'll need to complete the calculation before you hit the Post Comment button.

If you want to object to a comment made by another visitor, be sure to contact me and I'll look into it ASAP. Don't forget to mention the page link, or the QuickDocId of the document.

For more information about the Talk Back feature, check out this news item.