ChatGPT解决这个技术问题 Extra ChatGPT

NOT using repository pattern, use the ORM as is (EF)

I always used Repository pattern but for my latest project I wanted to see if I could perfect the use of it and my implementation of “Unit Of Work”. The more I started digging I started asking myself the question: "Do I really need it?"

Now this all starts with a couple of comments on Stackoverflow with a trace to Ayende Rahien's post on his blog, with 2 specific,

repository-is-the-new-singleton

ask-ayende-life-without-repositories-are-they-worth-living

This could probably be talked about forever and ever and it depends on different applications. Whats I like to know,

would this approach be suited for a Entity Framework project? using this approach is the business logic still going in a service layer, or extension methods (as explained below, I know, the extension method is using NHib session)?

That's easily done using extension methods. Clean, simple and reusable.

public static IEnumerable GetAll(
    this ISession instance, Expression<Func<T, bool>> where) where T : class
{
    return instance.QueryOver().Where(where).List();
}

Using this approach and Ninject as DI, do I need to make the Context a interface and inject that in my controllers?


u
user247702

I've gone down many paths and created many implementations of repositories on different projects and... I've thrown the towel in and given up on it, here's why.

Coding for the exception

Do you code for the 1% chance your database is going to change from one technology to another? If you're thinking about your business's future state and say yes that's a possibility then a) they must have a lot of money to afford to do a migration to another DB technology or b) you're choosing a DB technology for fun or c) something has gone horribly wrong with the first technology you decided to use.

Why throw away the rich LINQ syntax?

LINQ and EF were developed so you could do neat stuff with it to read and traverse object graphs. Creating and maintain a repository that can give you the same flexibility to do that is a monstrous task. In my experience any time I've created a repository I've ALWAYS had business logic leak into the repository layer to either make queries more performant and/or reduce the number of hits to the database.

I don't want to create a method for every single permutation of a query that I have to write. I might as well write stored procedures. I don't want GetOrder, GetOrderWithOrderItem, GetOrderWithOrderItemWithOrderActivity, GetOrderByUserId, and so on... I just want to get the main entity and traverse and include the object graph as I so please.

Most examples of repositories are bullshit

Unless you are developing something REALLY bare-bones like a blog or something your queries are never going to be as simple as 90% of the examples you find on the internet surrounding the repository pattern. I cannot stress this enough! This is something that one has to crawl through the mud to figure out. There will always be that one query that breaks your perfectly thought out repository/solution that you've created, and it's not until that point where you second guess yourself and the technical debt/erosion begins.

Don't unit test me bro

But what about unit testing if I don't have a repository? How will I mock? Simple, you don't. Lets look at it from both angles:

No repository - You can mock the DbContext using an IDbContext or some other tricks but then you're really unit testing LINQ to Objects and not LINQ to Entities because the query is determined at runtime... OK so that's not good! So now it's up to the integration test to cover this.

With repository - You can now mock your repositories and unit test the layer(s) in between. Great right? Well not really... In the cases above where you have to leak logic into the repository layer to make queries more performant and/or less hits to the database, how can your unit tests cover that? It's now in the repo layer and you don't want to test IQueryable<T> right? Also let's be honest, your unit tests aren't going to cover the queries that have a 20 line .Where() clause and .Include()'s a bunch of relationships and hits the database again to do all this other stuff, blah, blah, blah anyways because the query is generated at runtime. Also since you created a repository to keep the upper layers persistence ignorant, if you now you want to change your database technology, sorry your unit tests are definitely not going to guarantee the same results at runtime, back to integration tests. So the whole point of the repository seems weird..

2 cents

We already lose a lot of functionality and syntax when using EF over plain stored procedures (bulk inserts, bulk deletes, CTEs, etc.) but I also code in C# so I don't have to type binary. We use EF so we can have the possibility of using different providers and to work with object graphs in a nice related way amongst many things. Certain abstractions are useful and some are not.


You do not create repositories to be able to unit test them. You create repositories to be able to unit test the business logic. As for making sure that queries work: it's much easier to write integration tests for repositories as they only contain logic and not any business.
Coding for the exception: Using repositories is not to be able to switch database engine. It's about separating business from persistence.
These are all very valid points with a great deal of truth behind them. What is lacking however is the realization that LINQ strewn about an application instead of constrained to a consistent location creates the EF equivalent of SQL calls in codebehind pages. Every LINQ query is a potential maintenance point in an application, and the more there are (and the more widespread they are), the higher the maintenance costs and risks. Imagine adding a 'deleted' flag to an entity and having to locate every single place in a large application that entity is queried, having to modify each...
I think this is short-sighted and jaded. Why would you leak logic into the repo? And if you did, why would it matter? It's a data implementation. All we're doing is walling off the LINQ from the rest of the code by hiding it behind the repo. You say don't test it, but then you use not being able to test it as an argument against doing it. So make the repo, don't expose IQueryable, and don't test it. At least you can test everything else in isolation from the data implementation. And that 1% chance of a db change is still a huge one $-wise.
+1 for this answer. I find that we really do NOT need repositories with Entity Framework Core. The DbSet is the repository, and DbContext is the Unit of Work. Why implementing repository pattern when ORM already do that for us! For testing, just change the provider to InMemory. And do your tests! It is well documented in MSDN.
j
jgauffin

The repository pattern is an abstraction. It's purpose is to reduce complexity and make the rest of the code persistant ignorant. As a bonus it allows you to write unit tests instead of integration tests.

The problem is that many developers fail to understand the patterns purpose and create repositories which leak persistance specific information up to the caller (typically by exposing IQueryable<T>). By doing so they get no benefit over using the OR/M directly.

Update to address another answer

Coding for the exception

Using repositories is not about being able to switch persistence technology (i.e. changing database or using a webservice etc instead). It's about separating business logic from persistence to reduce complexity and coupling.

Unit tests vs integration tests

You do not write unit tests for repositories. period.

But by introducing repositories (or any other abstraction layer between persistance and business) you are able to write unit tests for the business logic. i.e. you do not have to worry about your tests failing due to an incorrectly configured database.

As for the queries. If you use LINQ you also have to make sure that your queries work, just as you have to do with repositories. and that is done using integration tests.

The difference is that if you have not mixed your business with LINQ statements you can be 100% sure that it's your persistence code that are failing and not something else.

If you analyze your tests you will also see that they are much cleaner if you have not mixed concerns (i.e. LINQ + Business logic)

Repository examples

Most examples are bullshit. that is very true. However, if you google any design pattern you will find a lot of crappy examples. That is no reason to avoid using a pattern.

Building a correct repository implementation is very easy. In fact, you only have to follow a single rule:

Do not add anything into the repository class until the very moment that you need it

A lot of coders are lazy and tries to make a generic repository and use a base class with a lot of methods that they might need. YAGNI. You write the repository class once and keep it as long as the application lives (can be years). Why fuck it up by being lazy. Keep it clean without any base class inheritance. It will make it much easier to read and maintain.

(The above statement is a guideline and not a law. A base class can very well be motivated. Just think before you add it, so that you add it for the right reasons)

Old stuff

Conclusion:

If you don't mind having LINQ statements in your business code nor care about unit tests I see no reason to not use Entity Framework directly.

Update

I've blogged both about the repository pattern and what "abstraction" really means: http://blog.gauffin.org/2013/01/repository-pattern-done-right/

Update 2

For single entity type with 20+ fields, how will you design query method to support any permutation combination? You dont want to limit search only by name, what about searching with navigation properties, list all orders with item with specific price code, 3 level of navigation property search. The whole reason IQueryable was invented was to be able to compose any combination of search against database. Everything looks great in theory, but user's need wins above theory.

Again: An entity with 20+ fields is incorrectly modeled. It's a GOD entity. Break it down.

I'm not arguing that IQueryable wasn't made for quering. I'm saying that it's not right for an abstraction layer like Repository pattern since it's leaky. There is no 100% complete LINQ To Sql provider (like EF).

They all have implementation specific things like how to use eager/lazy loading or how to do SQL "IN" statements. Exposing IQueryable in the repository forces the user to know all those things. Thus the whole attempt to abstract away the data source is a complete failure. You just add complexity without getting any benefit over using the OR/M directly.

Either implement Repository pattern correctly or just don't use it at all.

(If you really want to handle big entities you can combine the Repository pattern with the Specification pattern. That gives you a complete abstraction which also is testable.)


Not exposing IQueryable leads to limited search, and people end up creating more Get methods for different type of queries, and eventually it makes repository more complex.
you have not addressed the core issue at all: Exposing IQueryable through a repository is not a complete abstraction.
Having a query object which contains all the needed infrastructure to be executed in and of itself is the way to go imo. You give it the fields which are the search terms and it returns a list of results. Internal to the QO you can do whatever you want. And it is an interface, so easily tested. See my post above. It is the best.
Personally, I think it also makes sense to implement the IQueryable interface on a Repository class, rather than expose the underlying set in one of its members.
@yat: One repos per aggregate root. But imho it's not aggregate root and aggregate of tables but just aggregate root and aggregates. The actual storage might use just one table or lots of them, i.e. it may not be a one-one mapping between each aggregate and a table. I use repositories to reduce complexity and remove any dependencies of the underlying storage.
C
Community

IMO both the Repository abstraction and the UnitOfWork abstraction have a very valuable place in any meaningful development. People will argue about implementation details, but just as there are many ways to skin a cat, there are many ways to implement an abstraction.

Your question is specifically to use or not to use and why.

As you have no doubt realised you already have both these patterns built into Entity Framework, DbContext is the UnitOfWork and DbSet is the Repository. You don’t generally need to unit test the UnitOfWork or Repository themselves as they are simply facilitating between your classes and the underlying data access implementations. What you will find yourself needing to do, again and again, is mock these two abstractions when unit testing the logic of your services.

You can mock, fake or whatever with external libraries adding layers of code dependencies (that you don’t control) between the logic doing the testing and the logic being tested.

So a minor point is that having your own abstraction for UnitOfWork and Repository gives you maximum control and flexibility when mocking your unit tests.

All very well, but for me, the real power of these abstractions is they provide a simple way to apply Aspect Oriented Programming techniques and adhere to the SOLID principles.

So you have your IRepository:

public interface IRepository<T>
    where T : class
{
    T Add(T entity);
    void Delete(T entity);
    IQueryable<T> AsQueryable();
}

And its implementation:

public class Repository<T> : IRepository<T>
    where T : class
{
    private readonly IDbSet<T> _dbSet;
    public Repository(PPContext context) 
    {
        _dbSet = context.Set<T>();
    }

    public T Add(T entity)
    { 
        return _dbSet.Add(entity); 
    }

    public void Delete(T entity)
    {
        _dbSet.Remove(entity); 
    }

    public IQueryable<T> AsQueryable() 
    {
        return _dbSet.AsQueryable();
    }
}

Nothing out of the ordinary so far but now we want to add some logging - easy with a logging Decorator.

public class RepositoryLoggerDecorator<T> : IRepository<T>
    where T : class
{
    Logger logger = LogManager.GetCurrentClassLogger();
    private readonly IRepository<T> _decorated;
    public RepositoryLoggerDecorator(IRepository<T> decorated)
    {
        _decorated = decorated;
    }

    public T Add(T entity)
    {
        logger.Log(LogLevel.Debug, () => DateTime.Now.ToLongTimeString() );
        T added = _decorated.Add(entity);
        logger.Log(LogLevel.Debug, () => DateTime.Now.ToLongTimeString());
        return added;
    }

    public void Delete(T entity)
    {
        logger.Log(LogLevel.Debug, () => DateTime.Now.ToLongTimeString());
        _decorated.Delete(entity);
        logger.Log(LogLevel.Debug, () => DateTime.Now.ToLongTimeString());
    }

    public IQueryable<T> AsQueryable()
    {
        return _decorated.AsQueryable();
    }
}

All done and with no change to our existing code. There are numerous other cross cutting concerns we can add, such as exception handling, data caching, data validation or whatever and throughout our design and build process the most valuable thing we have that enables us to add simple features without changing any of our existing code is our IRepository abstraction.

Now, many times I have seen this question on StackOverflow – “how do you make Entity Framework work in a multi tenant environment?”.

https://stackoverflow.com/search?q=%5Bentity-framework%5D+multi+tenant

If you have a Repository abstraction then the answer is “it’s easy add a decorator”

public class RepositoryTennantFilterDecorator<T> : IRepository<T>
    where T : class
{
    //public for Unit Test example
    public readonly IRepository<T> _decorated;
    public RepositoryTennantFilterDecorator(IRepository<T> decorated)
    {
        _decorated = decorated;
    }

    public T Add(T entity)
    {
        return _decorated.Add(entity);
    }

    public void Delete(T entity)
    {
        _decorated.Delete(entity);
    }

    public IQueryable<T> AsQueryable()
    {
        return _decorated.AsQueryable().Where(o => true);
    }
}

IMO you should always place a simple abstraction over any 3rd party component that will be referenced in more than a handful of places. From this perspective an ORM is the perfect candidate as it is referenced in so much of our code.

The answer that normally comes to mind when someone says “why should I have an abstraction (e.g. Repository) over this or that 3rd party library” is “why wouldn’t you?”

P.S. Decorators are extremely simple to apply using an IoC Container, such as SimpleInjector.

[TestFixture]
public class IRepositoryTesting
{
    [Test]
    public void IRepository_ContainerRegisteredWithTwoDecorators_ReturnsDecoratedRepository()
    {
        Container container = new Container();
        container.RegisterLifetimeScope<PPContext>();
        container.RegisterOpenGeneric(
            typeof(IRepository<>), 
            typeof(Repository<>));
        container.RegisterDecorator(
            typeof(IRepository<>), 
            typeof(RepositoryLoggerDecorator<>));
        container.RegisterDecorator(
            typeof(IRepository<>), 
            typeof(RepositoryTennantFilterDecorator<>));
        container.Verify();

        using (container.BeginLifetimeScope())
        {
            var result = container.GetInstance<IRepository<Image>>();

            Assert.That(
                result, 
                Is.InstanceOf(typeof(RepositoryTennantFilterDecorator<Image>)));
            Assert.That(
                (result as RepositoryTennantFilterDecorator<Image>)._decorated,
                Is.InstanceOf(typeof(RepositoryLoggerDecorator<Image>)));
        }
    }
}

Interestingly, this answer is still relevant in 2020. Not much has changed since then. Not many methods to replace RP
A
Akash Kava

First of all, as suggested by some answer, EF itself is a repository pattern, there is no need to create further abstraction just to name it as repository.

Mockable Repository for Unit Tests, do we really need it?

We let EF communicate to test DB in unit tests to test our business logic straight against SQL test DB. I don't see any benefit of having mock of any repository pattern at all. What is really wrong doing unit tests against test database? As it is bulk operations are not possible and we end up writing raw SQL. SQLite in memory is perfect candidate for doing unit tests against real database.

Unnecessary Abstraction

Do you want to create repository just so that in future you can easily replace EF with NHbibernate etc or anything else? Sounds great plan, but is it really cost effective?

Linq kills unit tests?

I will like to see any examples on how it can kill.

Dependency Injection, IoC

Wow these are great words, sure they look great in theory, but sometimes you have to choose trade off between great design and great solution. We did use all of that, and we ended up throwing all at trash and choosing different approach. Size vs Speed (Size of code and Speed of development) matters huge in real life. Users need flexibility, they don't care if your code is great in design in terms of DI or IoC.

Unless you are building Visual Studio

All these great design are needed if you are building a complex program like Visual Studio or Eclipse which will be developed by many people and it needs to be highly customizable. All great development pattern came into picture after years of development these IDEs has gone through, and they have evolved at place where all these great design patterns matter so much. But if you are doing simple web based payroll, or simple business app, it is better that you evolve in your development with time, instead of spending time to build it for million users where it will be only deployed for 100s of users.

Repository as Filtered View - ISecureRepository

On other side, repository should be a filtered view of EF which guards access to data by applying necessary filler based on current user/role.

But doing so complicates repository even more as it ends up in huge code base to maintain. People end up creating different repositories for different user types or combination of entity types. Not only this, we also end up with lots of DTOs.

Following answer is an example implementation of Filtered Repository without creating whole set of classes and methods. It may not answer question directly but it can be useful in deriving one.

Disclaimer: I am author of Entity REST SDK.

http://entityrestsdk.codeplex.com

Keeping above in mind, we developed a SDK which creates repository of filtered view based on SecurityContext which holds filters for CRUD operations. And only two kinds of rules simplify any complex operations. First is access to entity, and other is Read/Write rule for property.

The advantage is, that you do not rewrite business logic or repositories for different user types, you just simply block or grant them the access.

public class DefaultSecurityContext : BaseSecurityContext {

  public static DefaultSecurityContext Instance = new DefaultSecurityContext();

  // UserID for currently logged in User
  public static long UserID{
       get{
             return long.Parse( HttpContext.Current.User.Identity.Name );
       }
  }

  public DefaultSecurityContext(){
  }

  protected override void OnCreate(){

        // User can access his own Account only
        var acc = CreateRules<Account>();

        acc.SetRead( y => x=> x.AccountID == UserID ) ;
        acc.SetWrite( y => x=> x.AccountID == UserID );

        // User can only modify AccountName and EmailAddress fields
        acc.SetProperties( SecurityRules.ReadWrite, 
              x => x.AccountName,
              x => x.EmailAddress);

        // User can read AccountType field
        acc.SetProperties<Account>( SecurityRules.Read, 
              x => x.AccountType);

        // User can access his own Orders only
        var order = CreateRules<Order>();
        order.SetRead( y => x => x.CustomerID == UserID );

        // User can modify Order only if OrderStatus is not complete
        order.SetWrite( y => x => x.CustomerID == UserID 
            && x.OrderStatus != "Complete" );

        // User can only modify OrderNotes and OrderStatus
        order.SetProperties( SecurityRules.ReadWrite, 
              x => x.OrderNotes,
              x => x.OrderStatus );

        // User can not delete orders
        order.SetDelete(order.NotSupportedRule);
  }
}

These LINQ Rules are evaluated against Database in SaveChanges method for every operation, and these Rules act as Firewall in front of Database.


Unit testing against a DB means you have extra outside requirement for your tests. If that DB is down, or the data gets cleared, or anything happens to that DB your tests will fail. This isn't desired. Repositories that expose IQueryable take about 2 mins to setup. No time wasted here. Why did DI take you a long time? All of this takes mins. I'll say this all worked great for unit testing my complex queries in my service layer. It was so nice not needing a database to connect to. Getting a mocking framework from nuget took about a min. This stuff doesn't take any time.
@user441521 Repositories with IQueryable 2 mins to setup? which world you are living in, every asp.net request on our live site is served within milliseconds. Mocking and faking etc adds more complexity to code, its total waste of time. Unit tests are useless when unit is not defined as business logic unit.
d
denis morozov

There is a lot of debate over which method is correct, so I look at it as both are acceptable so I use ever which one I like the most (Which is no repository, UoW).

In EF UoW is implemented via DbContext and the DbSets are repositories.

As for how to work with the data layer I just directly work on the DbContext object, for complex queries I will make extension methods for the query that can be reused.

I believe Ayende also has some posts about how abstracting out CUD operations is bad.

I always make an interface and have my context inherit from it so I can use an IoC container for DI.


So the extension methods, how extensive are they? Lets say I need to get the state of another entity in my extension? That is my biggest concern right now. You mind showing some examples of extension methods?
ayende.com/blog/153473/… and ayende.com/blog/153569/…. (These are reviews of a architecture(Framework?) called s#arp lite. Mostly good but he disagrees with the repositories and CUD abstractions).
Its NHibernate based. Don't you got any examples using EF? And again when I need to call another entity how is that made best in the static extension method?
This is all well and good until a property of your domain object needs to be hydrated by data that is not stored in your database; or you need to drop down in to a technology that is more performant than your bloated ORM. OOPS! An ORM is simply NOT a replacement for a repository, it is an implementation detail of one.
A
Aratirn

What most apply over EF is not a Repository Pattern. It is a Facade pattern (abstracting the calls to EF methods into simpler, easier to use versions).

EF is the one applying the Repository Pattern (and the Unit of Work pattern as well). That is, EF is the one abstracting the data access layer so that the user has no idea they are dealing with SQLServer.

And at that, most "repositories" over EF are not even good Facades as they merely map, quite straightforwardly, to single methods in EF, even to the point of having the same signatures.

The two reasons, then, for applying this so-called "Repository" pattern over EF is to allow easier testing and to establish a subset of "canned" calls to it. Not bad in themselves, but clearly not a Repository.


m
mikalai

Linq is a nowadays 'Repository'.

ISession+Linq already is the repository, and you need neither GetXByY methods nor QueryData(Query q) generalization. Being a little paranoid to DAL usage, I still prefer repository interface. (From maintainability point of view we also still have to have some facade over specific data access interfaces).

Here is repository we use - it de-couples us from direct usage of nhibernate, but provides linq interface (as ISession access in exceptional cases, which are subject to refactor eventually).

class Repo
{
    ISession _session; //via ioc
    IQueryable<T> Query()
    {
        return _session.Query<T>();
    }
}

What do you do for service layer?
Controllers query repo for read-only data, why add some extra layer? The other possibility is using "ContentService" which more and more tends to be a service-level-repository: GetXByY, etc.etc. For modification operations - application services are just abstractions over use cases - they use BL and repo freely..
I'm used to do service layer for business logic. I'm not really sure I follow what you with ContentService, please elaborate. Would it be bad practice to do helper classes as "service layer"?
By 'service layer' I meant 'application services'. They can use repository and any other public part of domain layer. "Service layer" isn't bad practice, but I'd avoid making XService class just to provide List result. Comment field seems to be too short to describe services in details, sorry.
What if, lets say a cart calculation and you need to get application settings parameters and specific customer parameters to make a calculation, and this is reused on several places in the application. How do you handle that situation? helper class or application service?
h
h.alex

The Repository (or however one chooses to call it) at this time for me is mostly about abstracting away the persistence layer.

I use it coupled with query objects so I do not have a coupling to any particular technology in my applications. And also it eases testing a lot.

So, I tend to have

public interface IRepository : IDisposable
{
    void Save<TEntity>(TEntity entity);
    void SaveList<TEntity>(IEnumerable<TEntity> entities);

    void Delete<TEntity>(TEntity entity);
    void DeleteList<TEntity>(IEnumerable<TEntity> entities);

    IList<TEntity> GetAll<TEntity>() where TEntity : class;
    int GetCount<TEntity>() where TEntity : class;

    void StartConversation();
    void EndConversation();

    //if query objects can be self sustaining (i.e. not need additional configuration - think session), there is no need to include this method in the repository.
    TResult ExecuteQuery<TResult>(IQueryObject<TResult> query);
}

Possibly add async methods with callbacks as delegates. The repo is easy to implement generically, so I am able not to touch a line of the implementation from app to app. Well, this is true at least when using NH, I did it also with EF, but made me hate EF. 4. The conversation is the start of a transaction. Very cool if a few classes share the repository instance. Also, for NH, one repo in my implementation equals one session which is opened at the first request.

Then the Query Objects

public interface IQueryObject<TResult>
{
    /// <summary>Provides configuration options.</summary>
    /// <remarks>
    /// If the query object is used through a repository this method might or might not be called depending on the particular implementation of a repository.
    /// If not used through a repository, it can be useful as a configuration option.
    /// </remarks>
    void Configure(object parameter);

    /// <summary>Implementation of the query.</summary>
    TResult GetResult();
}

For the configure I use in NH only to pass in the ISession. In EF makes no sense more or less.

An example query would be.. (NH)

public class GetAll<TEntity> : AbstractQueryObject<IList<TEntity>>
    where TEntity : class
{
    public override IList<TEntity> GetResult()
    {
        return this.Session.CreateCriteria<TEntity>().List<TEntity>();
    }
}

To do an EF query you would have to have the context in the Abstract base, not the session. But of course the ifc would be the same.

In this way the queries are themselves encapsulated, and easily testable. Best of all, my code relies only on interfaces. Everything is very clean. Domain (business) objects are just that, e.g. there is no mixing of responsibilities like when using the active record pattern which is hardly testable and mixes data access (query) code in the domain object and in doing so is mixing concerns (object which fetches itself??). Everybody is still free to create POCOs for data transfer.

All in all, much code reuse and simplicity is provided with this approach at the loss of not anything I can imagine. Any ideas?

And thanks a lot to Ayende for his great posts and continued dedication. Its his ideas here (query object), not mine.


Persistence entities (your POCOs) are NOT business/domain entities. And repository's purpose is to decouple business (ar any) layer from the persistence.
I fail to see the coupling. Somewhat agree on the POCO part, but don't care. Nothing to stop you from having 'genuine' POCOs and still use this approach.
Entities don't have to be dumb POCOs at all. In fact, modeling business logic into Entities is what the DDD crowd does all the time. This style of development blends very well with NH or EF.
C
Chalky

For me, it's a simple decision, with relatively few factors. The factors are:

Repositories are for domain classes. In some of my apps, domain classes are the same as my persistence (DAL) classes, in others they are not. When they are the same, EF is providing me with Repositories already. EF provides lazy loading and IQueryable. I like these. Abstracting/'facading'/re-implementing repository over EF usually means loss of lazy and IQueryable

So, if my app can't justify #2, separate domain and data models, then I usually won't bother with #5.