Skip to main content
Code Review

Return to Answer

Commonmark migration
Source Link

###Rewind.

Rewind.

###Enter EF.

Enter EF.

###Rewind.

###Enter EF.

Rewind.

Enter EF.

replaced http://stackoverflow.com/ with https://stackoverflow.com/
Source Link

You mock IDbSet<T> mock IDbSet<T> and the interface your DbContext is implementing. Simple as that.

You mock IDbSet<T> and the interface your DbContext is implementing. Simple as that.

You mock IDbSet<T> and the interface your DbContext is implementing. Simple as that.

added 1695 characters in body
Source Link
Mathieu Guindon
  • 75.5k
  • 18
  • 194
  • 467

The idea behind abstracting the database stuff, is that you need to be able to test/run your business code without actually hitting the database. I use something like this:

public interface IUnitOfWork
{
 void Commit();
 IDbSet<T> Set<T>();
}

The IDbSet<T> can be mocked (you Setup the return value of Set<T>()), and by coding against this IUnitOfWork, you have an abstraction you can use to mock your DbContext:

public class MyContext : DbContext, IUnitOfWork
{
 public void Commit()
 {
 SaveChanges();
 }
 public IDbSet<Foobar> Foobars { get; set; }
 // ...
}

The "repositories" become an implementation detail, they're just for EF to pick up: your code is working against an IDbSet<TEntity> - does that not look just about exactly like a generic repository?

So does this mean EF should be tightly coupled to my domain layer [...]?

If you're coding against IUnitOfWork, you have a loose enough coupling to test everything you need to test, without hitting a database. Yes, you're using an interface (IDbSet<T>) that is essentially some EntityFrameworkRepository<TEntity>... but to swap for a NHibernateRepository<TEntity> you'd have to reimplement all the seam-level code anyway, leaked or not; the business-layer code only ever needs to see/use an IEnumerable<TEntity>, and the TEntity in question. By reusing your entity classes, and only ever exposing a group of them as an IEnumerable<TEntity>, you pretty much shield your business code from even noticing that it's no longer Entity Framework providing them with this TEntity.


The idea behind abstracting the database stuff, is that you need to be able to test/run your business code without actually hitting the database. I use something like this:

public interface IUnitOfWork
{
 void Commit();
 IDbSet<T> Set<T>();
}

The IDbSet<T> can be mocked (you Setup the return value of Set<T>()), and by coding against this IUnitOfWork, you have an abstraction you can use to mock your DbContext:

public class MyContext : DbContext, IUnitOfWork
{
 public void Commit()
 {
 SaveChanges();
 }
 public IDbSet<Foobar> Foobars { get; set; }
 // ...
}

The "repositories" become an implementation detail, they're just for EF to pick up: your code is working against an IDbSet<TEntity> - does that not look just about exactly like a generic repository?

So does this mean EF should be tightly coupled to my domain layer [...]?

If you're coding against IUnitOfWork, you have a loose enough coupling to test everything you need to test, without hitting a database. Yes, you're using an interface (IDbSet<T>) that is essentially some EntityFrameworkRepository<TEntity>... but to swap for a NHibernateRepository<TEntity> you'd have to reimplement all the seam-level code anyway, leaked or not; the business-layer code only ever needs to see/use an IEnumerable<TEntity>, and the TEntity in question. By reusing your entity classes, and only ever exposing a group of them as an IEnumerable<TEntity>, you pretty much shield your business code from even noticing that it's no longer Entity Framework providing them with this TEntity.

Source Link
Mathieu Guindon
  • 75.5k
  • 18
  • 194
  • 467
Loading
lang-cs

AltStyle によって変換されたページ (->オリジナル) /