I'm new to this pattern and I see arguments online about different implementations. I have the following code and it seems fine to me, but I'm wondering if having to pass the DBContext into the constructor would cause any issues down the line? I'm using this with EntityFramework (RECORD_TYPE is a table brought in from EF).
I'm a little newer to unit testing as well, so I'm thinking I would have to make a mock context in my unit tests that basically return a list of RECORD_TYPE objects that I create in the mock DBContext I make.
Am I missing any ideas with this?
public interface IRepository<T> where T : class
{
IQueryable<T> All { get; }
T Find(int id);
void Save();
}
public class Repository<T> : IRepository<T> where T : class
{
private DbContext context;
public Repository(DbContext c)
{
context = c;
}
public IQueryable<T> All { get { return context.Set<T>(); } }
public T Find(int id)
{
return context.Set<T>().Find(id);
}
public void Save()
{
context.SaveChanges();
}
}
public class RecordTypeRepository : Repository<RECORD_TYPE>
{
public RecordTypeRepository(DbContext context)
: base(context)
{
}
}
-
\$\begingroup\$ you might want to read this: wekeroad.com/2014/03/04/… \$\endgroup\$Zdeslav Vojkovic– Zdeslav Vojkovic2014年04月07日 21:53:56 +00:00Commented Apr 7, 2014 at 21:53
-
\$\begingroup\$ @Zdeslav this is exactly the reason I made this post. When you search this online you get a million different ways and views on it. It's enough to drive a person insane. However, the reason I was looking into it was because of doing unit tests. I don't want to hit my database (and everything I do uses a database) because I don't want to have my database be in the right state (it's a pain). So I want an easy way to mock the db context so I can manually fill it with data to use for testing. This then opens up a big wormhole in all the possibilities. \$\endgroup\$user441521– user4415212014年04月07日 22:02:16 +00:00Commented Apr 7, 2014 at 22:02
1 Answer 1
In my opinion using the repository pattern is absolutely fine, for a number of reasons, not limited to:
- It enables unit testing
- Allows you to change EF for a another DB technology
The detail that you have to be careful of using the base class is that you make sure that you declare properties/variables via the interface and not via the base class. So consider this:
Good
public class Test{
private IRepository<MyClass> _repo;
}
Bad
public class Test{
private BaseRepository<MyClass> _repo;
}
With the actual code, I would suggest a number of changes:
- The interface should have full CRUD operations
- Try and use the same name for fetching a record (Consider
Get()
andGet(id)
vsAll()
andGet(1)
. It makes it more natural to consumers) - The class
Repository
should be marked as abstract to stop you using it directly - The class
Repository
should probably be namedEFBaseRepository
Typically, when I implement the pattern I create the interface followed by a class called BaseRepository
that implements all the methods. The methods no nothing more than throw a NotSupportedException
/NotImplementedException
. This is because I might only want consumers to have read/update but not create. It does depend on the context of the application.
Explore related questions
See similar questions with these tags.