user9993
user9993

Reputation: 6180

Naming conventions for methods in Repository pattern?

I'm trying to learn better software design and recently found the Repository and Service Layer patterns. From my understanding, the repository basically contains the data access code and the service layer calls the repository to get that data and then performs some logic and processing to that data.

So far from reading up on these there is, generally, not a set series of methods that the repository has. However, the repository usually has methods along these lines:

I'm trying to understand the naming conventions for repositories. What should I call the "List/Get/Read/etc." method? I'll give an example.

I'm currently working on a project that will read from a bunch of directories and files. These files represent sensor readings that are being generated by a completely separate and already existing system.

Should method names be specific to that particular type of repository or go for more generic sounding names? Such as:

Generic names:

interface ISensorRepository
{
    IEnumerable<Sensor> GetAll(); /  IEnumerable<Sensor> ListAll(); / etc.
    Sensor GetByID(int id);
}

Entity specific names:

interface ISensorRepository
{
    IEnumerable<Sensor> GetAllSensors(); / IEnumerable<Sensor> ListAllSensors(); / etc.
    Sensor GetSensorByID(int id);
}

Upvotes: 9

Views: 22112

Answers (3)

Arvin Yorro
Arvin Yorro

Reputation: 12167

I'll go with OP's first option the "generic naming"

Why? its to avoid smurf naming convention (it's a programming jargon), its what you do when you keep repeating yourself.

You already named the type of entity the repository represents, why go through all the work repeating yourself? If you stick with Single Responsibility Principle, you don't have to worry about your abstraction being leaky.

The following is what I try to avoid:

Employee
- EmployeeID
- EmployeeFirstName
- EmployeeLastName
- EmployeeAddress
- EmployeeNumber
- EmployeeAge
- EmployeeEmail
- EmployeeHiringDate
- EmployeeThis
- EmployeeThat
- EmployeeBlabla
- Employee...
- Employee...

Its kind of crazy right?

Upvotes: 7

3dd
3dd

Reputation: 2530

Martin Fowler in POEAA defined Repository as a mediator between domain and data mapping layers and that it acts like an in-memory domain object collection.

As it should act like an in memory collection, I like naming my methods as follows.

public interface IRepository<T> where T : class {
    T Create(T entity);

    void Create(IList<T> entities);

    T Update(T entity);

    T FirstOrDefault(Expression<Func<T, bool>> clause);

    IEnumerable<T> Where(Expression<Func<T, bool>> clause);

    IEnumerable<TResult> Select<TResult>(Expression<Func<T, TResult>> selector);

    T First();

    IEnumerable<T> All();
}

See http://martinfowler.com/eaaCatalog/repository.html for a short discussion around the pattern

Upvotes: 5

JounceCracklePop
JounceCracklePop

Reputation: 348

Consider what repository variables are likely to be named by the consumer. I would write something like:

public void DoSomethingWithSensors(ISensorRepository sensors)
{
    //Which looks better?
    foreach (var sensor in sensors.All)
    //Or:
    foreach (var sensor in sensors.GetAllSensors())
}

I generally like to avoid redundancy whenever possible. People aren't likely to forget which repository they're calling All on, so I'd name it that, and use similar generic names for other operations. This also gives you the advantage that you can abstract the basic interface into one generic type:

public interface IRepository<T>
{
    IQueryable<T> All { get; }
    void Update(T entity);
    T Get(int id); //If you have a standard type for IDs
    //etc.
 }

I would avoid methods like (not to pick on 3dd's nice answer):

T FirstOrDefault(Expression<Func<T, bool>> clause);
List<TResult> Select<TResult>(Expression<Func<T, TResult>> selector);

If you go down this route, you may find you're soon declaring all of LINQ in your interface. Just expose one IQueryable<T> and rely on LINQ to provide all those options. I'd stick to IQueryable over IEnumerable if you're using EntityFramework.

Another consideration is that this pattern is likely to break the Interface Segregation Principle. A lot of your consumers will only grab IRepository instances to query, never to write. Whether or not the added complexity of breaking it into two interfaces is worth addressing this problem depends on the expected lifecycle of your software and whether lots of other systems are likely to depend on your code.

Upvotes: 0

Related Questions