views:

236

answers:

3

I'm reading the book "ASP.NET 3.5 Social Networking - Andrew Siemer" and I got confused when he uses Repositories to access the data.

Here is the idea of his code:

public interface IAccountRepository
{
  Account GetAcountByID(int acId);
  void SaveAccount(Account account);
  List<Account> GetAllAccounts();      
}

public class AccountRepositoryLINQ : IAccountRepository
{
  Account GetAcountByID(int acId){
    ..... LINQ query ..... 
    ...... return.....
  }
  void SaveAccount(Account account){
    ..... LINQ ..... 
  }
  List<Account> GetAllAccounts(){
    ..... LINQ query ..... 
    ...... return.....
  }
}

The class "Account" is the one generated automatically on the "LINQ to SQL Classes".

Some of the problems I see:

I code my business layer, GUI, etc... and later in time the table Accounts in the database is changed (example: change the name of one column), then I need to rebuild the "LINQ to SQL Classes" and all my code layers will need to be recoded because my "Account" object changed.

If I need to have other repositories (MySQL, Oracle, XML, other), what "Account" class will I use?

What to do?

  • Shouldn't I use a custom Account class? This will be used in all application layers.
  • How do the mapping from LINQ to my custom Account class?
    • Using simple "myClass.Name = linqClass.Name;" ???
      • Isn't this consuming machine resources if I need to "map" all the classes?
      • There isn't a easiest/lightest way to do it?
      • Is this the correct approach? Is there other ways?
+2  A: 

Good instinct..

My suggestion is to abstract away the LinqToSQL objects, and create a set of Business Domain Objects. Then the Repository can query for the needed data and map them to the Domain objects that your application uses, and return those. Now your Data Access layer is decoupled from your application, and you can now do all of the things you listed.

The mapping can be a pain, so look at tools like Automapper to accomplish this.

jlembke
A: 

I personally use a combination of NHibernate and FluentNHibernate and seperate my domain(business objects) from all other things. I use messages from my other layers, like a GUI, to my domain which has a handler which injects repositories inside that hydrate the object(s) in question and perform the business logic, the interfaces in the repositories above are a nice way to decouple if you want to use other implementations of repositories or data access.

Brandon Grossutti
A: 

I have a love hate relationship with LINQ to SQL classes myself, but I thought I'd play devils advocate :-), firstly addressing the points you made:-

1º I code my business layer, GUI, etc... and later in time the table Accounts in the database is changed (example: change the name of one column), then I need to rebuild the "LINQ to SQL Classes" and all my code layers will need to be recoded because my "Account" object changed.

The general approach is that you'd add behaviour to the partial classes generated by LINQ to SQL, these files won't be replaced when you refresh a table from the data context. If you change the name of the column and don't want to change the rest of your code just update the class in the designer to use the old column name?

Even if you used POCOs for persistence with NHibernate for instance you'd still need to change the mapping so I don't really see this as an issue.

2º If I need to have other repositories (MySQL, Oracle, XML, other), what "Account" class will I use?

Personally I'd call YAGNI on this one, if you really anticipate needing support for multiple databases LINQ to SQL might not be the best solution to start with in any case (simply to keep your infrastructure consistent across the application), tools like NHibernate would have far better support for such situations.

Moving on to adding a custom account class, mapping code can be taken care of by tools like AutoMapper, though this might mean you give up things like lazy loading (which may or may not be a big deal to you).

In the end it can be quite empowering to have full control over your entities (e.g. not having to use a parameterless constructor, control over instatiation etc, simple user types that map to one or two columns) and if you feel that your application might benefit from this it's probably the way to go, but you will pay the price in the repository implementation which will be complicated by mapping code and handling whether things need to be updated / deleted / inserted.

A good middle ground might be to simply code to an interface (e.g. IAccount) this should define the properties and method you expect from an account. Your repository would then become

 IAccount GetById(int accountId);

You'll then give yourself freedom over what the implementation is (i.e. whether it's implemented by a LINQ to SQL class or a projection / mapping) and if you do opt for a custom class in future it'd be a simple case of moving the implementation to that class and altering the repository implementation.

In the end it's down to the application, if you think it's going to end up a huge application with extremely complex business logic by all means I would opt for a segregated domain layer that at least tries to be persistence ignorant. If, however, it isn't and opting for the repository pattern is simply a means to achieve good testability and a simple abstraction above your data access. I don't see why explicitly referencing LINQ to SQL classes and using them as a simple domain layer is such a big deal.

sighohwell