16

I know there are a lot of threads here already on the repository pattern but somehow I feel my question is a little different. Maybe because yesterday was the first time I heard of the word POCO.

My question is this--usually, I have add and save methods in my business entities. Say I am writing a Q/A site, and I have the following entities: questions, answers, and comments. If I wanted to use the repository pattern, I basically need to keep only the properties in my business entities (example, Question), and move my operations to the repository class (example, QuestionRepository), right? If this is true, does POCO mean a business entity with just the properties?

I'm using Entity Framework 4.0, which created my entities in the edmx code behind. If I wanted to use the repository pattern with this, there is no need to write my own business entities (Question, Answer, etc) since they are already generated by EF, right? All I'd need is the Repository to do CRUD? And I'll be having three repositories for this example, one for each entity?

Arnis Lapsa
  • 45,880
  • 29
  • 115
  • 195
Prabhu
  • 12,995
  • 33
  • 127
  • 210
  • 6
    Upvoted to cancel out unexplained downvote – Tom Bushell Sep 15 '10 at 17:45
  • I downvoted for the "somehow I feel my question is a little different" purposeful duplicate explanation. This is a triple dupe. "Do I need ViewModels?", "One repository per Entity?", "What are POCOs in EF" have all been answered before and are easily available via the search. – John Farrell Sep 15 '10 at 18:05

3 Answers3

35

First an observation about Asp.net MVC project template

I must say that there is a tiny misunderstanding with Visual Studio's Asp.net MVC project template. And that is the Model folder. People not knowing MVC pattern would automatically relate this to data model and not MVC application/presentation model. This is fine for simple applications where we don't distinguish between the two but not for anything else.

Let's continue to my answer

When I write business level applications I separate my solution into 4 projects (at least):

  • presentation tier - Asp.net MVC application but I remove Model folder and have all my views as strong type views to avoid magic strings as much as possible
  • service tier - business logic processes
  • data tier - data model ie. EF4 and repositories that access this model
  • objects tier - this project actually has POCOs that are used for inter-layer communication and any interfaces used by various layers (think of IoC)

My request process usually looks very clean and works this way:

  1. When a request is made my Asp.net MVC controller action validates data (POCO objects), does whatever is necessary for the presentation tier before calling into services.
  2. Service is called that does whatever business process logic requires and normally calls repository to do something with data.
  3. Repository manipulates data in the data model and then creates POCOs from results that will be returned to service layer.
  4. Service layer receives POCOs does additional logic if needed and returns them back to presentation.
  5. Presentation (controller) decides which view to display and provides model for that particular view and returns it. Of course instead of a view it can be any other result as well.

Advantage of using separate MVC model classes in Objects project (you couldn't put them in the Model folder because of circular project reference) is that I can have presentation optimised classes. Or better said: I have business process centric interface instead of data centric.

Let's explain this with an example: Take for instance user registration view. It can't be strong typed to data model's User entity. Why? Because it has two inputs for password. So I can have an application/presentation model class called UserRegistration even though there's nothing similar in data model. Its validation works completely differently compared to data model's User entity. If I'd have my user registration done without strong type I'd have to make my controller action with all parameters of every single field. These wouldn't be automatically validated which would mean that I can have a larger bug surface. Someone might hurry into writing code but forget about certain aspects of validation.

Strong type views returning strong types back at server are the safest way of getting rid of all kinds of obscure bugs that are usually discovered by users especially if you don't do any methodical testing on your project (which is somewhere between 75-90% chance).

Robert Koritnik
  • 103,639
  • 52
  • 277
  • 404
  • 3
    I can't upvote this enough! I've said the exact thing many times and I usually get comments to the regard of YAGNI or I'm crazy, which tells me most people are just writing simple CRUD apps that wouldn't benefit from these ideas. It's the primary reason I'm not very active here anymore. Any suggestion beyond "do what MSFT says" gets ignored by most people. – Ryan Sep 15 '10 at 19:51
  • 1
    @Ryan: Thank you very much. Though I haven't seen developers here blind-following some company's views. At least not as much to draw me away from the site. – Robert Koritnik Sep 15 '10 at 20:28
  • I'm trying to visualize this... In this model, does the *data layer* with the *repositories* return POCOs because the data layer _references_ the object layer and thus can build them? Or do you have a separate *interfaces* layer? – devlord Nov 29 '12 at 00:29
  • 1
    @lorddev: *objects tier* defines all types that are shared by individual tiers: POCO application-model classes, service interfaces, repository interfaces etc. Especially with nicely designed services and repositories you will be able to reuse interfaces for both. Maybe each also having a separate service interface vs. repository interface. But you will likely cover CRUD scenarios in both where each would be consuming and outputting POCOs. **To answer your question**: yes all layers strictly communicate via POCOs. Including repositories that create app-layer POCO instances from data... – Robert Koritnik Nov 29 '12 at 10:57
  • @RobertKoritnik Awesome answer +1. Just a couple of small questions. Your object layer is basically housing the (view)models that get passed form your controller to your view, right? Also, I assume we map the domain models (entities returned by the service layer to the presentation layer) to the view model inside the controller? – Mohammad Sepahvand Jan 09 '13 at 07:31
  • @MohammadSepahvand: All special non-data model classes (ie `UserRegistration`) are part of the **Objects** layer. They're used for inter-layer communication. I could name my *Objects* assembly as *DomainModel* or *ApplicationModel* or whatever, but I find it simpler by naming it *Objects*. **But beware** don't put any purely presentation-specific classes in here, because you may change presentation layer or add a new one (i.e. mobile app). Some specific presentation classes that get converted before calling into Services should be part of presentation layer... – Robert Koritnik Jan 09 '13 at 13:48
  • @MohammadSepahvand: Basically these domain classes are used to give views strong types whenever appropriate. But (as per my previous comment) whenever a view requires a particular class just because it's required by the presentation layer implementation that view will use that presentation layer specific class. Example of such class would likely be a set of various unrelated entities because view needs to display them. This may be quite common in MVC although not encouraged because it adds unnecessary complexity. – Robert Koritnik Jan 09 '13 at 13:52
  • Thanks @RobertKoritnik: any chance that you can post a screenshot of one of your sample solutions showing the 4 layers, all expanded? – Prabhu Apr 03 '13 at 04:00
  • @Prabhu: which additional details are you interested in? I may help in a different way maybe. – Robert Koritnik Apr 03 '13 at 07:54
  • @RobertKoritnik no big deal...your answer was clear, just thought it would help to visualize the actual structure to confirm what I've understood... – Prabhu Apr 03 '13 at 22:44
9

I was in a very similar place as the OP sometime ago, so I'll expand on Roberts answer with some code of how I structured my asp.net mvc app after learning about the repository pattern.

So your project is QandA

You'll have a class library project called QandA.data, here is where you will create your edmx file and all your entity framework classes. Then you have a repository for each entity like this:

public interface IRepository<T>
{
    T Save(T entity);
    void Delete(T entity);
    IQueryable<T> GetAll();
    T GetById(int id);
}

You could then have either a factory or use Dependency Injection to get the actually repositories. So:

class QuestionRepo : IRepository<Question>
{
 //call xxxEntites and get/save/delete yourentities here.
}
static class RepositoryFactory
{
 public static IRepository<Question> GetQuestionRepo()
 {
  return new QuestionRepo();
 }
}

Then down in your calling code (in your asp.net project) you have

IRepository<Question> qRepo = RepositoryFactory.GetQuestionRepo();
Question q =  qRepo.GetById(1);

Now the advantage of doing the above is, your calling code has no idea how the entities are coming through, so you could create a mock repository to test your app out.

static class RepositoryFactory
{
 public static IRepository<Question> GetQuestionRepo()
 {
  return new FakeQuestionRepo();
  //create your own fake repo with some fixed fake data.
 }
}

Now you're calling code does not change at all if you throw it a fake or real repository.

Also, what robert talks about in his question is a ViewModel. So you would not make a strongly typed page of type Question. So you have

class QuestionForm
{
 public string Title
 public string QuestionContent
}

You're page is going to be of type QuestionForm but in your create controller, you will take the data from the question form, fill it in your Question entity and then send it off via the repository.

[HttpPost]
public ActionResult Create(QuestionForm quesfrm)
{
 IRepository<Question> qRepo = RepositoryFactory.GetQuestionRepo();
 Question ques = new Question {
 AskedDate = DateTime.Now,
 Title = quesfrm.Title,
 Content = QuestionContent
 }
  qRepo.Save(ques);
}

Robert mentions one of the reasons why you would do this, there are a few other reasons and you can read up more on view models on SO. Also check out the code for nerddinner

You may want to see these SO questions:
Should repositories implement IQueryable<T>?
Repository pattern: One repository class for each entity?

I hope it helped.

Community
  • 1
  • 1
gideon
  • 19,329
  • 11
  • 72
  • 113
5

Your POCO objects would still have methods on them for operations, but those operations would pertain to the business concerns of the entity not the persistence concerns(CRUD). If there are no business operations on your entites, then yes they will be just properties.

You wouldn't need to write your pocos from scratch if you are generating them but you may want to extend them with partial classes for business operations and non-persistent or calculated properties.

You could have a single repository class or a repository for each entity.

PhilB
  • 11,732
  • 2
  • 19
  • 15
  • 1
    I think this is incorrect - if you're using the repository pattern your business objects don't contain the operations - that is all delegated to repositories. So your User object will have a Name, Surname, etc but your UserRepository object will have GetUsers and SaveUser methods – Jaco Pretorius Sep 16 '10 at 08:34
  • 2
    @Jaco Pretorius: The question object could have operations for AddAnswer, Close, SelectAnswer, etc which would be business concerns. The question object would not have operations for Save, Get, Update, or Delete as these are persistence concerns and would be the responsibility of the repository. Having no operations on your business objects leads to an anemic domain model http://en.wikipedia.org/wiki/Anemic_Domain_Model which is often considered an anti-pattern. – PhilB Sep 16 '10 at 14:10
  • I agree with PhilB, we use only repository for persistent concerns, entity can has as many its own operation as needed for handling its business logic. – Tien Do Sep 17 '10 at 03:42