简体   繁体   中英

What is best practise for repository pattern - repo per table?

The repository pattern seems to work well when working with an initial project with several large main tables.

However as the project grows it seems a little inflexible. Say you have lots of child tables that hang off the main table, do you need a repository for each table?

Eg

CustomerAddress Record has following child tables:

-> County

-> Country

-> CustomerType

On the UI, 3 dropdown lists need to be displayed, but it gets a bit tedious writing a repository for each of the above tables which selects the data for the dropdowns.

Is there a best practice/more efficient way of doing this?

As an example say you have a main CustomerAddress repository which I guess is the 'aggregate root' which inherits the main CRUD operations from the base repo interface.

Previously I have short-cutted the aggregate root and gone straight to the context for these kinds of tables.

eg

public Customer GetCustomerById(int id)
{
  return Get(id);
}

public IEnumerable<Country> GetCountries()
{
  return _ctx.DataContext.Countries.ToList();
}

etc...

But sometimes it doesn't feel right, as countries aren't part of the customer, but I feel like I need to tack it onto something without having to create zillions of repos for each table. A repo per table definately doesn't seem right to me either.

I would certainly not create a repository per table. On the contrary: I would define one generic repository that works for every table. By doing this you save yourself a lot of code, and when you implement IQueryable on that class, it will allow you to use LINQ queries over it, and you can hide your O/RM framework behind an abstraction, which allows you to effectively write unit tests. I wrote an article on this, see Faking your LINQ provider .

Responding to the questioner's own answer : This doesn't make sense to me; though it's possible you still had a good use case, I'm not following. Points 1 and 2... if you need specialized methods, then looks like they belong in their own repo. Point 2: yes, that needs an implementation.

Sharing between repos, with the smaller repo being the question (is that one needed), I do appreciate that question / problem, but guys' on this thread steered me to being okay with 1 repo per table, including the possibility of having a 'service layer', though they didn't give any examples of that, and I haven't tried this out yet (currently my practice, for good or ill, has been to have the bigger repo share or instantiate the smaller one it needs):

One repository per table or one per functional section?

First the code you posted is not the repository pattern. Where is the collection like interface? If it is an aggregate it should only be returning the aggregate type.

Repository pattern doesn't offer up much flexibility when it comes being able to select different types. Repository pattern follows a collection interface (insert/add/update/delete/get/etc), mirroring an in memory thing, and it generally only retrieves on type. So if you were to use the repository pattern you would need to select all CustomerAddresses and then* filter the countries out. I would suggest you move to a different pattern, that allows for more flexibility aka DAO.

If these things are always going to be maintained through CustomerAddress, then switch patterns and create a DAO class that offers some other getters for the other types of things you need.


On a more generic note, build for need .

Never just blindly create repository classes, its a maintenance nightmare. The only time I would argue for a repo per table is when you are doing CMS like things, and need to be able create everything.

Example:

So you have a CustomerAddress which ties together a Customer and a Country, but you have some other process that needs to be able to CRUD the Country. As a result you need* the repository to manipulate Country and if you are following DRY you dont want to have duplicate logic to manipulate Countries. What you would have is a Customer Respotitory that uses the Country repository.

I'm answering my own question here because while the suggestions are certainly useful, I feel I have a better solution. While I don't have to phsyically create the underlying repository for each and every table as I have a generic repository base class with interface (Get, Add, Remove), I still have to:

1) write the interface to access any specialised methods (generally these are queries)

2) write those implementations

I don't necessarily want to do this when all I want to retrieve is a list of countries or some simple type for populating a dropdown. Think of effort required if you have 10 reference type tables.

What I decided to do was create a new class called SimpleRepo with ISimpleRepo interface which exposes 1-2 methods. While I don't normally like to expose the IQueryable interface out of the repo i/f class, I don't mind here as I want the provided flexibility. I can simply expose a 'Query()' method which provides the flexibility hook. I might need this for specialising the ordering, or filtering.

Whenever a service needs to make use of some simple data, the ISimple< T > interface is passed in, where T is the table/class.

I now avoid the need to create an interface/class for these simple pieces of data. Thoughts anyone?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM