I have the following class:
public class InMemoryRepository : IRepository
{
public void Add(object entity)
{
throw new NotImplementedException();
}
public void Attach(object Entity)
{
throw new NotImplementedException();
}
public T Get<T>(object id)
{
throw new NotImplementedException();
}
public IList<T> GetAll<T>(string queryName)
{
throw new NotImplementedException();
}
public IList<T> GetAll<T>()
{
throw new NotImplementedException();
}
public IQueryable<T> Query<T>()
{
throw new NotImplementedException();
}
public void Remove(object entity)
{
throw new NotImplementedException();
}
public void Save(object entity)
{
throw new NotImplementedException();
}
}
Our default repository implementation uses NHibernate for the backing store, but I'd like to implement an in-memory version of it so I can prototype the domain objects without having to create a backing SQL database. Assuming the convention that all objects have an Id property as the primary key, how would you implement a generic memory store for this?
Some key points I'm having a hard time addressing:
The repository methods themselves are generic, so I need some mechanism for automatically storing and referencing different types. Get<TestEntity>(object id) should be able to query all stored instances of TestEntity and find the one with the matching Id property, but I can't define a collection of TestEntity objects directly, as the repository won't know what types I'm feeding it until runtime.
I need to support LINQ to Objects for the Query() method. Assuming I can come up with a decent way to store the objects, this should be as simple as returning an array of stored objects AsQueryable().
How would you store the objects to meet the above requirements?
Basics are simple:
public class InMemoryRepository : IRepository
{
private readonly IList<object> entities = new List<object>();
public T Get<T>(object id)
{
return entities.OfType<T>.SingleOrDefault(e => e.ID == id);
}
public IList<T> GetAll<T>()
{
return entities.OfType<T>.ToList();
}
public IQueryable<T> Query<T>()
{
return GetAll<T>.AsQueryable();
}
}
However, as soon as it comes to public IList<T> GetAll<T>(string queryName), things get complicated.
Potentially you can resort to an SQLite-based repository implementation for your tests.
I would go with NHibernate configured for in-memory SqlLite database. You can test then your real code and be sure that everything works correct. Writing mock for Repository can be hard and if you change IRepository interface you will have to reimplement you InMemoryRepository.
For me one of big benefits of having NHibernate is the possibility for using in memory database for testing.
With Anton's answer I was able to fix my own InMemoryRepository. I have modified it to match the class in the question:
private readonly ConcurrentDictionary<Type, List<object>> ObjectList = new ConcurrentDictionary<Type, List<object>>();
public int Add<T>(T obj) where T : IIdentifier
{
// instantiate if list does not exist for this object type
if (!ObjectList.ContainsKey(typeof (T)))
ObjectList[typeof(T)] = new List<object>();
// get id
var id = GetId<T>() + 1;
// add object to list
obj.Id = id;
ObjectList[typeof(T)].Add(obj);
return id;
}
public void Attach<T>(T obj) {
// do not need to do anything
}
public T Get<T>(int id) where T : class, IIdentifier
{
// check list exist
if (!ObjectList.ContainsKey(typeof (T)))
return null;
return ObjectList[typeof(T)].OfType<T>().FirstOrDefault(n => n.Id == id);
}
public List<T> GetAll<T>(Func<T, bool> predicate) where T : new()
{
// check list exist
if (!ObjectList.ContainsKey(typeof(T)))
return null;
return ObjectList[typeof(T)].OfType<T>().Where(predicate).ToList();
}
public List<T> GetAll<T>()
{
return ObjectList[typeof(T)].OfType<T>.ToList();
}
public IQueryable<T> Query<T>()
{
return GetAll<T>.AsQueryable();
}
public int Remove<T>(int id) where T : IIdentifier
{
// check list exist
if (!ObjectList.ContainsKey(typeof(T)))
return 0;
// find object with matching id
for (var i = 0; i < ObjectList[typeof(T)].Count; i++)
if (ObjectList[typeof(T)].OfType<T>().ToList()[i].Id == id)
{
ObjectList[typeof(T)].RemoveAt(i);
return id;
}
// object not found
return 0;
}
public int Save<T>(T obj) where T : IIdentifier
{
// check list exist
if (!ObjectList.ContainsKey(typeof(T)))
return 0;
// find object with matching id
for (var i = 0; i < ObjectList[typeof(T)].Count; i++)
if (ObjectList[typeof(T)].OfType<T>().ToList()[i].Id == obj.Id)
{
ObjectList[typeof (T)][i] = obj;
return obj.Id;
}
// object not found
return 0;
}
#region Helper methods
private int GetId<T>() where T : IIdentifier
{
return ObjectList[typeof(T)].Count == 0 ? 0 : ObjectList[typeof(T)].OfType<T>().Last().Id;
}
#endregion
Here is an implementation of fake repository based on DbSet, including find by primary keys:
http://refactorthis.wordpress.com/2011/11/30/generic-repository-fake-idbset-implementation-update-find-method-identity-key/
Related
I'm having some trouble creating my own List structure. I'm trying to create a List structure called SortedList. The objective is for it to Sort its items as soon as add a new item. This list will not get too big in the project I'm using it for (maybe 50-100 items at most). However, I was testing by adding a simple item of class Employee which has a Name property. And I want this SortedList to sort on employee's Name.
Here is my attempt.
The Employee class
public class Employee : IComparer<Employee>
{
public string Name { get; set; }
public Employee()
{
}
public int Compare(Employee x, Employee y)
{
return string.Compare(x.Name, y.Name,true);
}
}
Here is the SortedList class that I'm trying to create.
public class SortedList<T> : IEnumerable<T>
{
private List<T> _list;
public List<T> List
{
get { return _list; }
set { _list = value; }
}
private Employee EmployeeComparer = new Employee();
public SortedList()
{
_list = new List<T>();
}
public void Insert(T item)
{
if (!_list.Contains(item))
{
_list.Add(item);
Sort(_list);
}
}
private void Sort(List<T> list)
{
var type = typeof(T);
switch (type.Name)
{
case "Int32":
case "String":
list.Sort();
break;
case "Employee":
Employee EmployeeComparer = new Employee();
list.Sort(EmployeeComparer);
break;
}
}
public IEnumerator<T> GetEnumerator()
{
return _list.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
From program.cs I'm basically populating the SortedList with three instances of Employee objects and I expect it to Sort it by employee's Name property and in the out put I expect to see this.
Barry
Neil
Zach
class Program
{
static void Main(string[] args)
{
SortedList<Employee> list = new SortedList<Employee>();
list.Insert(new Employee() { Name="Zach"});
list.Insert(new Employee() { Name = "Neil" });
list.Insert(new Employee() { Name = "Barry" });
foreach (var item in list)
{
Console.WriteLine(item.Name);
}
}
}
But I get a compiler error. It says:
Severity Code Description Project File Line Suppression State
Error CS1503 Argument 1: cannot convert from 'ExtensingLists.Employee' to 'System.Collections.Generic.IComparer<T>' ExtensingLists C:\E Drive\VSProjects\C-Sharp Generics Course\ExtensingLists\ExtensingLists\SortedList.cs 57 Active
The error says line 57, which is this:
list.Sort(EmployeeComparer);
What am I doing wrong? Please advise. Thank you.
The concrete question you're asking about is like asking why
int f(object o) { return o is int ? o : 0; }
fails to compile. Even if you've checked that o has type int at run-time, at compile-time it still has type object, which means it can't be used as the return value. You'd need a cast to get that working:
int f(object o) { return o is int ? (int)o : 0; }
and the same applies to your code.
But there's something more fundamentally wrong. Your Employee shouldn't be implementing IComparer<Employee>. It should be implementing IComparable<Employee>, which specifies not that an Employee object knows how to compare two other Employee objects, but that it knows how to compare itself to another Employee object. And when you do that, you should be able to just call list.Sort(); without checking the type at all.
The List.Sort method can be made to work in multiple ways.
This method uses the default comparer Comparer.Default for type T to determine the order of list elements. The Comparer.Default property checks whether type T implements the IComparable generic interface and uses that implementation, if available. If not, Comparer.Default checks whether type T implements the IComparable interface. If type T does not implement either interface, Comparer.Default throws an InvalidOperationException.
So by making the below change, it will start working for you
public class Employee : IComparable<Employee> {
public string Name { get; set; }
public Employee() {
}
public int CompareTo(Employee other) {
return string.Compare(Name, other.Name, true);
}
}
and the Below change in public class SortedList<T> : IEnumerable<T> {
private static void Sort(List<T> list) {
var type = typeof(T);
list.Sort();
}
This is not the only way to do, but a preferable way to do when the Types are intrinsically Orderable. You can also use the IComparer<T> interface, but that is used when the Type needs to be sorted in a way that IComparable<T> does not or when the Type is not an IComparable<T>. I have listed all the code here together
class Program {
static void Main() {
SortedList<Employee> list = new SortedList<Employee>();
list.Insert(new Employee() { Name = "Zach" });
list.Insert(new Employee() { Name = "Neil" });
list.Insert(new Employee() { Name = "Barry" });
foreach (var item in list) {
Console.WriteLine(item.Name);
}
}
}
public class Employee : IComparable<Employee> {
public string Name { get; set; }
public int Age { get; set; }
public Employee() {
}
public int CompareTo(Employee other) {
return string.Compare(Name, other.Name, true);
}
}
public class EmployeeAgeComparer : IComparer<Employee> {
public int Compare(Employee x, Employee y) {
return x.Age - y.Age;
}
}
public class SortedList<T> : IEnumerable<T> {
private List<T> _list;
public List<T> List {
get { return _list; }
set { _list = value; }
}
private EmployeeAgeComparer EmployeeComparer = new EmployeeAgeComparer();
public SortedList() {
_list = new List<T>();
}
public void Insert(T item) {
if (!_list.Contains(item)) {
_list.Add(item);
Sort(_list);
}
}
private void Sort(List<T> list) {
if (typeof(T) == typeof(Employee))
list.Sort((IComparer<T>)EmployeeComparer);
else
list.Sort();
}
public IEnumerator<T> GetEnumerator() {
return _list.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() {
return GetEnumerator();
}
}
How to set up where linq extension on object? DbSet in my case. Here is my code:
this.workflowStateSet
.Setup(m => m.Where(It.IsAny<Expression<Func<Model.WorkflowState, int, bool>>>()))
.Returns(new List<Model.WorkflowState>().AsQueryable());
However, it gives me exception not very familiar exception:
System.NotSupportedException: Expression references a method that
does not belong to the mocked object: m => m.Where<WorkflowState>
I will be grateful for any hint.
This extension method will help mock the DbSet
public static class MockDbSetExtensions {
public static Mock<DbSet<T>> AsDbSetMock<T>(this IEnumerable<T> list) where T : class {
IQueryable<T> queryableList = list.AsQueryable();
Mock<DbSet<T>> dbSetMock = new Mock<DbSet<T>>();
dbSetMock.As<IQueryable<T>>().Setup(x => x.Provider).Returns(queryableList.Provider);
dbSetMock.As<IQueryable<T>>().Setup(x => x.Expression).Returns(queryableList.Expression);
dbSetMock.As<IQueryable<T>>().Setup(x => x.ElementType).Returns(queryableList.ElementType);
dbSetMock.As<IQueryable<T>>().Setup(x => x.GetEnumerator()).Returns(() => queryableList.GetEnumerator());
return dbSetMock;
}
}
And you can use it like this.
//Arrange
var data = new List<Model.WorkflowState>();
//you would populate your list as needed.
//convert it to a mock DbSet that uses the list as its datasource
var workflowStateSet = data.AsDbSetMock();
var dbSet = workflowStateSet.Object;
//Act
var items = dbSet.Where("Your expression here");
//Assert
//....
Use the repository pattern to add a layer of abstraction to the data retrieval. This abstraction can then be mocked.
If, for example, you were trying to retrieve all of the workflows with a stateId equal to 1, then rather than calling something like this
var result = DbSet.WorkflowState.Where(w => w.stateId == 1);
move this code into another class and then create an interface of the method signature.
public interface IWorkflowStateSetRepository{
IQueryable<Model.WorkflowState> GetAllWorkflows(int state);
}
implementation
public class WorkflowStateSetRepository : IWorkflowStateSetRepository{
public IQueryable<Model.WorkflowState> GetAllWorkflows(int state){
return DbSet.WorkflowState .Where(w => w.stateId == state);
}
}
In the calling code get an instance of IWorkflowStateSetRepository (probably from your IoC container) and call the GetAllWorkflows() method instead. This will give you the same results as before but you can now mock the interface in your tests and setup calls to that methods.
this.MockedIWorkflowStateSetRepository.Setup(m => m.GetAllWorkflows(It.IsAny<int>()))
.Returns(new List<Model.WorkflowState>().AsQueryable());
This code is more maintainable and (with appropriately named variables and methods) also conveys the intent a lot better.
The repository pattern is discussed in greater detail here;
http://www.asp.net/mvc/overview/older-versions/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application
Are you trying to Mock up a real DbSet instance ? Cause this won't work, as the error message try to explain you. To mock a type, it must either be an interface or have virtual members (abstract members are also virtual).
You can try to mock up IDbSet or to create a custom DbSet class, for instance something like the following class
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;
public class DbSetMock<T> : DbSet<T>, IDbSet<T>
where T : class
{
private readonly ICollection<T> _contentCollection;
public DbSetMock(IList<T> contentCollection = null)
{
_contentCollection = new Collection<T>(contentCollection ?? new List<T>());
AddedEntities = new List<T>();
RemovedEntities = new List<T>();
AttachedEntities = new List<T>();
}
public void OverrideContentCollection(IEnumerable<T> newData)
{
_contentCollection.Clear();
_contentCollection.AddRange(newData);
}
public IList<T> AddedEntities { get; private set; }
public IList<T> AttachedEntities { get; private set; }
public override ObservableCollection<T> Local
{
get
{
throw new NotImplementedException();
}
}
public IList<T> RemovedEntities { get; private set; }
public Type ElementType
{
get
{
return typeof(T);
}
}
public Expression Expression
{
get
{
return _contentCollection.AsQueryable().Expression;
}
}
public IQueryProvider Provider
{
get
{
return _contentCollection.AsQueryable().Provider;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public IEnumerator<T> GetEnumerator()
{
return _contentCollection.GetEnumerator();
}
public override T Add(T entity)
{
AddedEntities.Add(entity);
_contentCollection.Add(entity);
return entity;
}
public override T Attach(T entity)
{
AttachedEntities.Add(entity);
var matchingEntity = _contentCollection.SingleOrDefault(x => x.Id == entity.Id);
if (matchingEntity != null)
{
_contentCollection.Remove(matchingEntity);
}
_contentCollection.Add(entity);
return entity;
}
public override TDerivedEntity Create<TDerivedEntity>()
{
throw new NotImplementedException();
}
public override T Create()
{
throw new NotImplementedException();
}
public override T Find(params object[] keyValues)
{
throw new NotImplementedException();
}
public override T Remove(T entity)
{
RemovedEntities.Add(entity);
_contentCollection.Remove(entity);
return entity;
}
}
You can use constructor parameter to setup content that will be retrieved by the db set.
Hope this helps.
I'm trying to create a unit test for my service with a mocked DbContext. I created an interface IDbContext with the following functions:
public interface IDbContext : IDisposable
{
IDbSet<T> Set<T>() where T : class;
DbEntityEntry<T> Entry<T>(T entity) where T : class;
int SaveChanges();
}
My real context implements this interface IDbContext and DbContext.
Now I'm trying to mock the IDbSet<T> in the context, so it returns a List<User> instead.
[TestMethod]
public void TestGetAllUsers()
{
// Arrange
var mock = new Mock<IDbContext>();
mock.Setup(x => x.Set<User>())
.Returns(new List<User>
{
new User { ID = 1 }
});
UserService userService = new UserService(mock.Object);
// Act
var allUsers = userService.GetAllUsers();
// Assert
Assert.AreEqual(1, allUsers.Count());
}
I always get this error on .Returns:
The best overloaded method match for
'Moq.Language.IReturns<AuthAPI.Repositories.IDbContext,System.Data.Entity.IDbSet<AuthAPI.Models.Entities.User>>.Returns(System.Func<System.Data.Entity.IDbSet<AuthAPI.Models.Entities.User>>)'
has some invalid arguments
I managed to solve it by creating a FakeDbSet<T> class that implements IDbSet<T>
public class FakeDbSet<T> : IDbSet<T> where T : class
{
ObservableCollection<T> _data;
IQueryable _query;
public FakeDbSet()
{
_data = new ObservableCollection<T>();
_query = _data.AsQueryable();
}
public virtual T Find(params object[] keyValues)
{
throw new NotImplementedException("Derive from FakeDbSet<T> and override Find");
}
public T Add(T item)
{
_data.Add(item);
return item;
}
public T Remove(T item)
{
_data.Remove(item);
return item;
}
public T Attach(T item)
{
_data.Add(item);
return item;
}
public T Detach(T item)
{
_data.Remove(item);
return item;
}
public T Create()
{
return Activator.CreateInstance<T>();
}
public TDerivedEntity Create<TDerivedEntity>() where TDerivedEntity : class, T
{
return Activator.CreateInstance<TDerivedEntity>();
}
public ObservableCollection<T> Local
{
get { return _data; }
}
Type IQueryable.ElementType
{
get { return _query.ElementType; }
}
System.Linq.Expressions.Expression IQueryable.Expression
{
get { return _query.Expression; }
}
IQueryProvider IQueryable.Provider
{
get { return _query.Provider; }
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return _data.GetEnumerator();
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return _data.GetEnumerator();
}
}
Now my test looks like this:
[TestMethod]
public void TestGetAllUsers()
{
//Arrange
var mock = new Mock<IDbContext>();
mock.Setup(x => x.Set<User>())
.Returns(new FakeDbSet<User>
{
new User { ID = 1 }
});
UserService userService = new UserService(mock.Object);
// Act
var allUsers = userService.GetAllUsers();
// Assert
Assert.AreEqual(1, allUsers.Count());
}
In case anyone is still interested, I was having the same problem and found this article very helpful:
Entity Framework Testing with a Mocking Framework (EF6 onwards)
It only applies to Entity Framework 6 or newer, but it covers everything from simple SaveChanges tests to async query testing all using Moq (and a few of manual classes).
Thank you Gaui for your great idea =)
I did add some improvements to your solution and want to share it.
My FakeDbSet also inherents from DbSet to get additional methods
like AddRange()
I replaced the ObservableCollection<T> with List<T> to pass all
the already implemented methods in List<> up to my FakeDbSet
My FakeDbSet:
public class FakeDbSet<T> : DbSet<T>, IDbSet<T> where T : class {
List<T> _data;
public FakeDbSet() {
_data = new List<T>();
}
public override T Find(params object[] keyValues) {
throw new NotImplementedException("Derive from FakeDbSet<T> and override Find");
}
public override T Add(T item) {
_data.Add(item);
return item;
}
public override T Remove(T item) {
_data.Remove(item);
return item;
}
public override T Attach(T item) {
return null;
}
public T Detach(T item) {
_data.Remove(item);
return item;
}
public override T Create() {
return Activator.CreateInstance<T>();
}
public TDerivedEntity Create<TDerivedEntity>() where TDerivedEntity : class, T {
return Activator.CreateInstance<TDerivedEntity>();
}
public List<T> Local {
get { return _data; }
}
public override IEnumerable<T> AddRange(IEnumerable<T> entities) {
_data.AddRange(entities);
return _data;
}
public override IEnumerable<T> RemoveRange(IEnumerable<T> entities) {
for (int i = entities.Count() - 1; i >= 0; i--) {
T entity = entities.ElementAt(i);
if (_data.Contains(entity)) {
Remove(entity);
}
}
return this;
}
Type IQueryable.ElementType {
get { return _data.AsQueryable().ElementType; }
}
Expression IQueryable.Expression {
get { return _data.AsQueryable().Expression; }
}
IQueryProvider IQueryable.Provider {
get { return _data.AsQueryable().Provider; }
}
IEnumerator IEnumerable.GetEnumerator() {
return _data.GetEnumerator();
}
IEnumerator<T> IEnumerable<T>.GetEnumerator() {
return _data.GetEnumerator();
}
}
It is very easy to modify the dbSet and Mock the EF Context Object:
var userDbSet = new FakeDbSet<User>();
userDbSet.Add(new User());
userDbSet.Add(new User());
var contextMock = new Mock<MySuperCoolDbContext>();
contextMock.Setup(dbContext => dbContext.Users).Returns(userDbSet);
Now it is possible to execute Linq queries, but be a aware that foreign key references may not be created automatically:
var user = contextMock.Object.Users.SingeOrDefault(userItem => userItem.Id == 42);
Because the context object is mocked the Context.SaveChanges() won't do anything and property changes of your entites might not be populated to your dbSet. I solved this by mocking my SetModifed() method to populate the changes.
Based on this MSDN article, I've created my own libraries for mocking DbContext and DbSet:
EntityFrameworkMock - GitHub
EntityFrameworkMockCore - GitHub
Both available on NuGet and GitHub.
The reason I've created these libraries is because I wanted to emulate the SaveChanges behavior, throw a DbUpdateException when inserting models with the same primary key and support multi-column/auto-increment primary keys in the models.
In addition, since both DbSetMock and DbContextMock inherit from Mock<DbSet> and Mock<DbContext>, you can use all features of the Moq framework.
Next to Moq, there also is an NSubstitute implementation.
Usage with the Moq version looks like this:
public class User
{
[Key, Column(Order = 0)]
public Guid Id { get; set; }
public string FullName { get; set; }
}
public class TestDbContext : DbContext
{
public TestDbContext(string connectionString)
: base(connectionString)
{
}
public virtual DbSet<User> Users { get; set; }
}
[TestFixture]
public class MyTests
{
var initialEntities = new[]
{
new User { Id = Guid.NewGuid(), FullName = "Eric Cartoon" },
new User { Id = Guid.NewGuid(), FullName = "Billy Jewel" },
};
var dbContextMock = new DbContextMock<TestDbContext>("fake connectionstring");
var usersDbSetMock = dbContextMock.CreateDbSetMock(x => x.Users, initialEntities);
// Pass dbContextMock.Object to the class/method you want to test
// Query dbContextMock.Object.Users to see if certain users were added or removed
// or use Mock Verify functionality to verify if certain methods were called: usersDbSetMock.Verify(x => x.Add(...), Times.Once);
}
If anyone is still looking for answers I've implemented a small library to allow mocking DbContext.
step 1
Install Coderful.EntityFramework.Testing nuget package:
Install-Package Coderful.EntityFramework.Testing
step 2
Then create a class like this:
internal static class MyMoqUtilities
{
public static MockedDbContext<MyDbContext> MockDbContext(
IList<Contract> contracts = null,
IList<User> users = null)
{
var mockContext = new Mock<MyDbContext>();
// Create the DbSet objects.
var dbSets = new object[]
{
MoqUtilities.MockDbSet(contracts, (objects, contract) => contract.ContractId == (int)objects[0] && contract.AmendmentId == (int)objects[1]),
MoqUtilities.MockDbSet(users, (objects, user) => user.Id == (int)objects[0])
};
return new MockedDbContext<SourcingDbContext>(mockContext, dbSets);
}
}
step 3
Now you can create mocks super easily:
// Create test data.
var contracts = new List<Contract>
{
new Contract("#1"),
new Contract("#2")
};
var users = new List<User>
{
new User("John"),
new User("Jane")
};
// Create DbContext with the predefined test data.
var dbContext = MyMoqUtilities.MockDbContext(
contracts: contracts,
users: users).DbContext.Object;
And then use your mock:
// Create.
var newUser = dbContext.Users.Create();
// Add.
dbContext.Users.Add(newUser);
// Remove.
dbContext.Users.Remove(someUser);
// Query.
var john = dbContext.Users.Where(u => u.Name == "John");
// Save changes won't actually do anything, since all the data is kept in memory.
// This should be ideal for unit-testing purposes.
dbContext.SaveChanges();
Full article: http://www.22bugs.co/post/Mocking-DbContext/
I'm late, but found this article helpful: Testing with InMemory (MSDN Docs).
It explains how to use an in memory DB context (which is not a database) with the benefit of very little coding and the opportunity to actually test your DBContext implementation.
I tried below Repository Pattern implementation
interface IRepository<T>
{
IQueryable<T> All { get; }
T Find(object id);
void Insert(T model);
}
Then i have IAdminRepository defined below
interface IAdminRepository : IRpository<Role>, IRepository<User>
{
}
public class AdminRepository:IAdminRepository
{
IQueryable<User> IRepository<User>.All
{
get { throw new NotImplementedException(); }
}
User IRepository<User>.Find(object id)
{
throw new NotImplementedException();
}
void IRepository<User>.Insert(User model)
{
throw new NotImplementedException();
}
IQueryable<Role> IRepository<Role>.All
{
get { throw new NotImplementedException(); }
}
Role IRepository<Role>.Find(object id)
{
throw new NotImplementedException();
}
void IRepository<Role>.Insert(Role model)
{
throw new NotImplementedException();
}
}
In my business layer i use Interface based calling.
public interface IAdminService
{
bool CreateUser(User user);
List<User> GetAllUsers();
}
public class AdminService : IAdminService
{
private readonly IAdminRepository AdminRepository;
public AdminService(IAdminRepository _adminRepository)
{
AdminRepository = _adminRepository;
}
public bool CreateUser(User user)
{
AdminRepository.Insert(user);
return true;
}
public List<User> GetAllUsers()
{
return AdminRepository.All; // Here is error
}
}
Error: Ambiguity between IRepository.All &
IRepository.All.
How to resolve this? What is the problem with my approach of using Repository Pattern in this way?
I guess this line
return AdminRepository.All; // Here is error
should be
return ((IRepository<User>)AdminRepository).All.ToList();
You probably noticed that you would not have been able to declare .All without explicitly writing which interface you were implementing. That's because, for a given class, two properties with the same name can not have different return types.
It is the same when invoking. You have to tell exactly which property you are invoking. This is done by casting the object to the desired interface.
Anyway, it seems you will end-up implementing the repositories for all of your entity types. You should just implement IRepository<T> once for entity types which can be retrieved from the same mechanism.
If you want your repository to apply only on some classes, you may, for example, tag these classes with an interface. Let's say IEntity.
public interface IEntity
{
}
then
public interface IRepository<T> where T:IEntity
{
IQueryable<T> All { get; }
T Find(object id);
void Insert(T model);
}
You can even have db repositories which only apply to entities you would have tagged as being db entities, like this :
public interface IDbEntity: IEntity
{
}
public class DbRepository<T> : IRepository<T> where T:IDbEntity
{
public IQueryable<T> All { get; private set; }
public T Find(object id)
{
throw new NotImplementedException();
}
public void Insert(T model)
{
throw new NotImplementedException();
}
}
A simple way to disambiguate the call is to create aliasing methods:
public class AdminRepository : IAdminRepository {
public IQueryable<User> AllUsers {
get { throw new NotImplementedException(); }
}
public IQueryable<Role> AllRoles {
get { throw new NotImplementedException(); }
}
IQueryable<User> IRepository<User>.All {
get { return AllUsers; }
}
IQueryable<Role> IRepository<Role>.All {
get { return AllRoles; }
}
...
}
Given this magical interface:
public interface IHat<out TRabbit>
{
TRabbit Take();
}
And this class hierarchy:
public class Rabbit { }
public class WhiteRabbit : Rabbit { }
I can now compile this:
IHat<WhiteRabbit> hat1 = null;
IHat<Rabbit> hat2 = hat1;
Which is great. But what if I define the interface differently:
public interface IHat<out TRabbit>
{
bool Take(out TRabbit r);
}
I'm indicating that the hat might be empty, using a separate boolean return value (the previous version would perhaps have returned a null rabbit from an empty hat). But I'm still only outputting a rabbit, so not doing anything logically different to the previous version.
The C# 4.0 compiler in the CTP gives an error in the interface definition - it requires 'out' method parameters to be of an invariant type. Is there a hard-and-fast reason why this isn't allowed, or is it something that might be addressed in a future version?
Interesting. However, at the CLI level there is no such thing as "out" - only "ref"; there is an attribute that helps compilers (for definite assignment) that says "you don't need to pass it in".
Maybe this restriction is because the CLI doesn't have "out", only "ref".
Although it's a bit of a hassle, you can use a covariance wrapper:
public class CovariantListWrapper<TOut, TIn> : IList<TOut> where TIn : TOut
{
IList<TIn> list;
public CovariantListWrapper(IList<TIn> list)
{
this.list = list;
}
public int IndexOf(TOut item)
{
// (not covariant but permitted)
return item is TIn ? list.IndexOf((TIn)item) : -1;
}
public TOut this[int index]
{
get { return list[index]; }
set { throw new InvalidOperationException(); }
}
public bool Contains(TOut item)
{
// (not covariant but permitted)
return item is TIn && list.Contains((TIn)item);
}
public void CopyTo(TOut[] array, int arrayIndex)
{
foreach (TOut t in this)
array[arrayIndex++] = t;
}
public int Count { get { return list.Count; } }
public bool IsReadOnly { get { return true; } }
public IEnumerator<TOut> GetEnumerator()
{
foreach (TIn t in list)
yield return t;
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public void Insert(int index, TOut item) { throw new InvalidOperationException(); }
public void RemoveAt(int index) { throw new InvalidOperationException(); }
public void Add(TOut item) { throw new InvalidOperationException(); }
public void Clear() { throw new InvalidOperationException(); }
public bool Remove(TOut item) { throw new InvalidOperationException(); }
}
This lets you keep the collection as it was originally typed and refer to it covariantly without creating a detached copy, so that updates to the original are seen in the covariant use. Example:
class CovarianceWrapperExample
{
class Person { }
class Employee : Person { }
void ProcessPeople(IList<Person> people) { /* ... */ }
void Foo()
{
List<Employee> employees = new List<Employee>();
// cannot do:
ProcessPeople(employees);
// can do:
ProcessPeople(new CovariantListWrapper<Person, Employee>(employees));
}
}