Repository pattern and return types

10,045

Solution 1

I personally use a generic type repository and and have my read AsQueryable()

Here's the interface.

interface IRepository<T>
{
    void Create(T item);
    IQueryable<T> Retrieve();
    void Update(T item);
    void Delete(T item);
    void SubmitChanges();
}

and here's the implementation.

public class PersonsRepository : IRepository<Person>
{
    private DataContext dc;

    public PersonsRepository(DataContext dataContext)
    {
        dc = dataContext;
    }

    public void Create(Person Person)
    {
        dc.Persons.Add(Person);
    }

    public IQueryable<Person> Retrieve()
    {
        IQueryable<Person> Person = (from s in dc.Persons
                                       select s);
        return Person.AsQueryable();

    }

    public void Update(Person Person)
    {
        Person _Person = (from s in dc.Persons
                            where s.ID == Person.ID
                            select s).Single();
        {
            _Person.LastLogin = Person.LastLogin;
            _Person.Password = Person.Password;
            _Person.LastUpdate = Person.LastUpdate;
            // Cannot change your username.
        }
    }

    public void Delete(Person Person)
    {
        dc.Persons.Remove(Person);
    }

    public void SubmitChanges()
    {
        dc.SaveChanges();
    }
}

Now if you need to query the repository, you want to do something like this.
forgive me, the below code is untested and I'm actually more of a VB guy :(
hopefully you get the point

public class PersonsService
{
    private PersonRepository<Person> personRepository;

    public PersonService()
    {
        personRepository = new PersonRepository<Person>();
    }

    public UsablePerson GetPersonByID(int ID)
    {
        UsablePerson person = (from p in personRepository<Person>.Retrieve
                               where p.ID = ID
                               select new UsablePerson { p.FirstName, 
                                                         p.LastName, 
                                                         p.EmailAddress }).FirstOrDefault();

        return person;
    }
}

For my purposes, I'm using LINQ on this particular project, but this can be adapted to whatever data layer you like... that's the beauty of a repository layer.

From here I "personally" also have a Service Layer that deals with the nuances of data connection... things like GetPersonByID or GetPeopleSince(DateTime marker). This is where I strip out the information that I don't need (IE: passwords) and store the remaining information in either a ViewModel or some other POCO.

Solution 2

I add methods to my repositories when I need them in contrast to generic repositories where you get a set of methods no matter if you need them or not.

Returning IQueryable is a leaky abstraction.

Take a look at Domain Driven Design (the book) and you'll get a good idea of how well designed repositories should look like.

I've also written a rant about generic repositories: http://blog.gauffin.org/2012/02/generic-repositories-a-silly-abstraction-layer/

Solution 3

If you think of Domain Driven Design, the fact a single object has different configuration most likely indicates different domains. This does not necessitate a different object for each, but it is a good pattern. One way to achieve this is have a base class ith the minimalist set of properties. You then create more "domain specific" classes that inherit from the base.

As for returning the data, there are a variety of ways of "traffic copping" the flow. Multiple repositories separate out the domains nicely, for example. But this adds complexity (not a good idea unless absolutely needed). I don't like a single repository returning different objects. It is more acceptable if you have some nullable properties (maybe).

I am not fond of LINQ to SQL as a DAL, as @KethiS has suggested, but I work in an Enterprise Environment and LINQ to SQL basically sucks at scale. Using LINQ otherwise is great. Just my two cents.

If you can return one object type, that is better. If the difference in the objects is based on permissions, consider clearing out the data the user should not see. Note, however, this is not as scalable if you are grabbing a large number of objects.

Solution 4

Why would you return all fields when you actually require only few of them? Select the fields that you really want if you are worried about performance. I'm not a big fan of strictly following a design pattern, maybe you should consider altering the design according to your requirement.

Share:
10,045
chobo
Author by

chobo

Updated on June 04, 2022

Comments

  • chobo
    chobo almost 2 years

    I am using the repository pattern where I have one repository class per database table. I was wondering how you guys approach queries that only need to return a specific number of columns

    For example say I have the following

    Item Table (fictional table)

    ItemId
    Name
    PurchaseDate
    Description
    Price
    

    In my code I create an object with the fields above called Item.cs (currently not using an orm).

    If I have multiple scenarios where I need to return

    1. ItemId
    2. A combination of PurchaseDate and Name
    3. ItemId and price

    Which would be the best approach?

    1. Get all fields from the items table and return an Item object (1 repo query)
    2. Create three queries in Repo and return an Item object for each one
    3. Create three queries in Repo and return only what is needed?

    Now imagine this scenario with a table with over 10 fields.

    Personally, I like option one, but I'm not sure if there is a better way to go about this.