views:

73

answers:

3

Hi all,

From one side, I want to write a killer app(in ASP.NET MVC) ;) But from the other side, I have many doubts if I should keep to so called "best practices" at all cost. So I have a design question and I really hope you can help me out.

Imagine a standard blog. I want to show 10 most recent posts. My database has standard
Posts, Categories, Tags, PostTags
tables. So as a natural consequence, my domain Post class has properties like this:

public Category Category { get; set; }
public virtual ICollection<Tag> Tags { get; set; }

I use EF4 with POCO support. And I load the data with a standard query:

from p in context.Posts.Include("Category").Include("Tags")
select p

But why should I load the entire Post class (with for example those 2 properties), when on the page all I want to show (besides the post itself) are links to category and each tag, so all the columns I need are:
[Categories].[Name], [Categories].[Slug], [Tags].[Name], [Tags.Slug].

I don't need the entire Category or Tag instance (which may have 100 columns in corresponding table in the database)! I imagine that when a site gets a lot of requests, it DOES matter. So it would be nice not to load all columns (avoid scary SELECT *).

I thought I can add a new class to my domain, say: ShortPost. But I feel it's not my domain! Post is the model, ShortPost is... well, just part of a complete Post. Besides - this ShortPost feels to me like modyfying/adjusting Domain (Model) just to please the View.

To sum up: should I really load the entire Model instance when on the View side I don't need the entire object? Can you please tell me about some preferred solutions/ways/etc?

A: 

Given your example - I would go with:

public class Post
{
    public Category Category {get;set;}
}
public class Tag
{
    public Post {get;set;}
}

That way it is far easier to query for exactly the tags you need for a given Post when you need them (You query Tag for those matching the Post instead of querying Post for Tags - thus giving you the abiltiy to page, filter etc. them).

As much as I can, I tend to avoid Collections (unless it is value objects that cannot exist without the parent object). It will be a lot easier to maintain in my experience.

And if you at some point need to show stats about your Post (how many tags it has attached and so on) - you can use 'views' of your data with just the data you need (equivalent to Views across tables in your DB). Views are outside your domain - thus you need not stick to the rules of your domain. Then when you go into 'edit mode' you load the full entity.

Goblin
Thx for a tip, but it didn't answer my question. I'm asking if it's ok (from a view of "best practices") to perform SELECT * in order to have fully loaded entities which than have many data that I simply don't need (in my View).
Darmak
The short answer is that it depends. Select * is only a problem if it is a problem (read: performance usually). Only do such optimizations if you are having problems.
Goblin
Hmm, that's a second vote for "yes" to load all data... I'm starting to think I'm overprotective :)
Darmak
Hehe - I've tried too many times to optimize before _knowing_ it was a problem only to learn that I won 5 ms in a 250 ms query after hours of hard work :).
Goblin
+1  A: 

Load the complete domain models- That way you can cache them an have the full object in the cache.

It would be confusing to have partly filled objects in the cache.

Malcolm Frexner
OK, that's an answer... but as a counter-argument I'll say: I'm scared that loading complete instances (which would mean e.g. 200 columns from a database) will be veeery slow - and in a webapp performance is pretty important.
Darmak
I completely forgot about caching... that will do the trick. Thanks very much for the concept :)
Darmak
+2  A: 

How about not using your Entities for reading? This is a characteristic of Command-Query Separation pattern.

If the only fields your View needs are [Categories].[Name], [Categories].[Slug], [Tags].[Name], [Tags.Slug]

Then create a DTO that represents this and populate it either by projecting off your entities or querying your datastore directly.

public class PostDto
{
    public string CategoryName { get; set; }

    public string CategorySlug { get; set; }

    public string TagName { get; set; }

    public string TagSlug { get; set; }

}
willbt
Yes, it will eliminate SELECT *, but PostDTO doesn't belong to the Model conceptually, so it shouldn't be used in my repositories to query the DB, should it?
Darmak
It belongs to the ViewModel but no it should not be referenced in your Repositories. In CQS you don't use Repositories for populating ViewModels but rather a thin Query layer and Repositories are only used for write operations or Commands.
willbt