views:

183

answers:

3

I am using repository pattern with linq to sql, I am using a repository class per table. I want to know , am i doing at good/standard way,

ContactRepository

  Contact GetByID()
  Contact GetAll()

COntactTagRepository

 List<ContactTag> Get(long contactID)
 List<ContactTag> GetAll()
 List<ContactTagDetail> GetAllDetails()

class ContactTagDetail
{
  public Contact Contact {get;set;}
  public ContactTag COntactTag {get;set;}
}

When i need a contact i call method in contactrepository, same for contacttag

but when i need contact and tags together i call GetDetais() in ContactTag repository its not returning the COntactTag entity generated by the orm insted its returning ContactTagDetail entity conatining both COntact and COntactTag generated by the orm, i know i can simple call GetAll in COntactTag repository and can access Contact.ContactTag but as its linq to sql it will there is no option to Deferred Load in query level, so whenever i need a entity with a related entity i create a projection class

Another doubt is where i really need to right the method i can do it in both contact & ContactTag repostitory like In contact repository GetALlWithTags() or something but i am doing it in in COntactTag repository

Whats your suggestions ?

+5  A: 

I haven't got time to go into detail, but basically don't have a one-to-one relationship between tables and your repositories. I've made that mistake, and it doesn't work. Instead, have your repository contain all the tables that are related conceptually. In your case, just have a Contact repository that handles both Contacts and ContactTags (and any other related tables). There is no rule on what "related" means, only you can decide - but govern your decision based on you understanding of how elements of your application are naturally grouped together.

Also have a read of these two threads on SO that deal with a similar issue:

Multiple or Single Repositories with LINQ and How to use the repository pattern correctly?

Dan Diplo
its good but when i have repository with many related entities where i will write the insert/delete etc methods ,
MindlessProgrammer
You could put them all in one repository, so long as they are related as a "unit of work".
Dan Diplo
A: 

I believe you're on the right track. One issue you will run into with linq to sql is the one to one mapping with tables. So you are forced to expose you many to many relation ship tables.

The way I have gotten around this is to use a data layer that has access to the linq to sql but maps everything back to POCO objects before returning the call.

 public IQueryable<ArtGalleryData.Image> GetImagesByImageGroup(int id)
    {

        return SqlDataContext.Image_ImageGroups
            .Where(iig => iig.ImageGroupID == id)
            .Join(
            SqlDataContext.Images,
            iig => iig.ImageID,
            i => i.ImageID,
            (iig, i) => new ArtGalleryData.Image 
            { ImageID = i.ImageID, 
              Description = i.Description, 
              Title = i.Title, 
              Height = i.Height, 
              Width = i.Width }).AsQueryable();
    }

Basically I'm mapping the linq object Image back to a POCO object Image. (I know its kind of messing but it the best example I have on hand.)

To get the effect of deferrd loading you would return a IQueryable <T> object. This will allow you to hold off on executoin of the query until you need to.

Also for objects with dependant collection in them I found this great helper class: LazyList it allows for lazy loading(deffered execution) of collections via IQueryable <T>

Most of what I know was from reading Rob Connerys Blog MVC Store Front.

Read his blog post and download the Store front project I think it will answer many of your questions. If your not using asp.net MVC just looking over his data access layer should be a huge help.

Hope That helps

Anthony
Rob Connery not Roby Cory
George Mauer
Whoops Thanks I will update my entry
Anthony
A: 

This is not the repository pattern. The repository pattern is basically creating an object that abstracts away persistence by acting (conceptually) as the collection of all objects of a certain type in the domain.

Therefore a contact repository might work something like this:

IContacts contacts = GetContactRepository();
using(var uow = UnitOfWork.Create()) {
  var contact1 = contacts.Get(new FindByNameSpecification("Fred"));
  contact1.LastName = "Rubble";
  var contact2 = new Contact("Barney", "Flistone");
  contacts.Add(contact2);
  // both contact1 and contact 2 are implicitly saved at the end of the unit of work
}  

a slightly looser definition of how the repository should work might be something like this:

IContactRepository contacts = GetContactRepository();
using(var uow = UnitOfWork.Create()) {
  var contact1 = contacts.GetByName("Fred");
  contact1.LastName = "Rubble";
  contacts.Save(contact1);
  var contact2 = new Contact("Barney", "Flistone");
  contacts.Save(contact2);
}  //The save is explicit but the commit is implicit

What you've got is a table data gateway.

The problem is that you are creating one gateway for each table. I would recommend against that.

Is tagging part of your contact domain or not? If it is then you should have the properties

public class Contact {
  public IEnumerable<Tag> Tags { get; }
  public void TagWith(Tag tag) { .... }
  public void UnTag(Tag tag) { ... }
}

Also, ask yourself will you ever add a tag that has zero contacts under it? If no then it gets even easier - you do not need a gateway to manage tags at all, just let your Contact object handle it

public interface IContactRepository {
  IEnumerable<Contact> GetAll(); // returns Contacts along with their tags
  void Save(Contact); // saves Contact along with any tags
} 

By the way, if tagging is not part of your domain (as in it is an application concern) then you should have a separate service, probably even in a separate project

public interface IAssociateTags {
  IEnumerable<Tag> GetTagFor(Contact contact);
  void TagContact(Contact contact, Tag tag);
  void UnTagContact(Contact contact, Tag tag);
}
George Mauer