NBuilder and DbContext invalid cast issue - nunit

I am really new to NBuilder, but it looks awesome so I thought I would have a go.
I have a DatabaseContext which just inherits from DbContext like this:
public class DatabaseContext : DbContext
Now, I have created a service that queries the DatabaseContext like this:
public async Task<List<Strategy>> Handle(StrategyList query, CancellationToken cancellationToken)
{
return _databaseContext.Strategies.ToList();
}
And now I want to make a test.
I set this Context up like this:
public class StrategyListContext
{
public readonly DatabaseContext DatabaseContext;
private StrategyListContext()
{
DatabaseContext = CreateDatabaseContext();
}
private DatabaseContext CreateDatabaseContext()
{
var dbContext = Substitute.For<DatabaseContext>();
var items = Builder<Strategy>.CreateListOfSize(10).Build();
dbContext.Strategies.ToList().Returns(items);
return dbContext;
}
public static StrategyListContext GivenServices() => new StrategyListContext();
public StrategyListHandler WhenCreateHandler() => new StrategyListHandler(DatabaseContext);
}
The most important part is the CreateDatabaseContext method.
It is like this:
private DatabaseContext CreateDatabaseContext()
{
var dbContext = Substitute.For<DatabaseContext>();
var items = Builder<Strategy>.CreateListOfSize(10).Build();
dbContext.Strategies.ToList().Returns(items);
return dbContext;
}
But when I run the test, I get this error:
System.InvalidCastException : Unable to cast object of type 'Castle.Proxies.ObjectProxy' to type 'Microsoft.EntityFrameworkCore.Metadata.Internal.Model'.
Does anyone know what I can do to get this working?
So I found this question:
How do I mock DbContext using NSubstitute and then add/remove data
And I have changed my method to this:
private DatabaseContext CreateDatabaseContext()
{
var dbContext = Substitute.For<DatabaseContext>();
var items = Builder<Strategy>.CreateListOfSize(10).Build().AsQueryable();
var dbSet = Substitute.For<DbSet<Strategy>, IQueryable<Strategy>>();
((IQueryable<Strategy>)dbSet).Provider.Returns(items.Provider);
((IQueryable<Strategy>)dbSet).Expression.Returns(items.Expression);
((IQueryable<Strategy>)dbSet).ElementType.Returns(items.ElementType);
((IQueryable<Strategy>)dbSet).GetEnumerator().Returns(items.GetEnumerator());
dbContext.Set<Strategy>().Returns(dbSet);
return dbContext;
}
But I still get the same error....

The second solution was soooo close, it was simply this:
private static DatabaseContext CreateDatabaseContext()
{
var dbContext = Substitute.For<DatabaseContext>();
var items = Builder<Hall>.CreateListOfSize(10).Build().AsQueryable();
var dbSet = Substitute.For<DbSet<Hall>, IQueryable<Hall>>();
((IQueryable<Hall>)dbSet).Provider.Returns(items.Provider);
((IQueryable<Hall>)dbSet).Expression.Returns(items.Expression);
((IQueryable<Hall>)dbSet).ElementType.Returns(items.ElementType);
((IQueryable<Hall>)dbSet).GetEnumerator().Returns(items.GetEnumerator());
dbContext.Halls = dbSet;
return dbContext;
}
NB: the line that states: dbContext.Halls = dbSet instead of dbContext.Set<Strategy>().Returns(dbSet);

Related

Entity Framework Core 1.1 In Memory Database fails adding new entities

I am using the following code in a unit test for the test setup:
var simpleEntity = new SimpleEntity();
var complexEntity = new ComplexEntity
{
JoinEntity1List = new List<JoinEntity1>
{
new JoinEntity1
{
JoinEntity2List = new List<JoinEntity2>
{
new JoinEntity2
{
SimpleEntity = simpleEntity
}
}
}
}
};
var anotherEntity = new AnotherEntity
{
ComplexEntity = complexEntity1
};
using (var context = databaseFixture.GetContext())
{
context.Add(anotherEntity);
await context.SaveChangesAsync();
}
When SaveChangesAsync is reached EF throws an ArgumentException with the following message:
An item with the same key has already been added. Key: 1
I'm using a fixture as well for the unit test class which populates the database with objects of the same types, though for this test I want this particular setup so I want to add these new entities to the in memory database. I've tried adding the entities on the DbSet (not the DbContext) and adding all three entities separatly to no avail. I can however add "simpleEntity" separately (because it is not added in the fixture) but EF complains as soon as I try to add "complexEntity" or "anotherEntity".
It seems like EF in memory database cannot handle several Add's over different instances of the context. Is there any workaround for this or am I doing something wrong in my setup?
The databaseFixture in this case is an instance of this class:
namespace Test.Shared.Fixture
{
using Data.Access;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
public class InMemoryDatabaseFixture : IDatabaseFixture
{
private readonly DbContextOptions<MyContext> contextOptions;
public InMemoryDatabaseFixture()
{
var serviceProvider = new ServiceCollection()
.AddEntityFrameworkInMemoryDatabase()
.BuildServiceProvider();
var builder = new DbContextOptionsBuilder<MyContext>();
builder.UseInMemoryDatabase()
.UseInternalServiceProvider(serviceProvider);
contextOptions = builder.Options;
}
public MyContext GetContext()
{
return new MyContext(contextOptions);
}
}
}
You can solve this problem by using Collection Fixtures so you can share this fixture across several test classes. This way you don't build you context several times and thus you won't get this exception:
Some information about collection Fixture
My own example:
[CollectionDefinition("Database collection")]
public class DatabaseCollection : ICollectionFixture<DatabaseFixture>
{ }
[Collection("Database collection")]
public class GetCitiesCmdHandlerTests : IClassFixture<MapperFixture>
{
private readonly TecCoreDbContext _context;
private readonly IMapper _mapper;
public GetCitiesCmdHandlerTests(DatabaseFixture dbFixture, MapperFixture mapFixture)
{
_context = dbFixture.Context;
_mapper = mapFixture.Mapper;
}
[Theory]
[MemberData(nameof(HandleTestData))]
public async void Handle_ShouldReturnCountries_AccordingToRequest(
GetCitiesCommand command,
int expectedCount)
{
(...)
}
public static readonly IEnumerable<object[]> HandleTestData
= new List<object[]>
{
(...)
};
}
}
Good luck,
Seb

Passing connection string to Entity framework at runt time for each call

My Entity framework context is as following
public partial class MyContext : DbContext, IMyContext
{
static MyContext()
{
System.Data.Entity.Database.SetInitializer<MyContext>(null);
}
public MyContext()
: base("Name=MyContext")
{
}
I am resolving it through autofac in the following way
builder.RegisterType(typeof(MainContext)).As(typeof(DbContext)).InstancePerLifetimeScope();
builder.RegisterType<MainContext>().As<IMainContext>().InstancePerRequest();
This db context gets called in repository layer
#region Fields
private readonly IMyContext _context;
#endregion
#region Constructors and Destructors
public EmployeeRepository(IMyContext context)
{
_context = context;
}
#endregion
public void Create(Employee emp)
{
this._context.Employee.Add(emp);
}
Now my issue is , I want to set the connection string dynamically per call. The connection string will be passed through a webapi which i want to pass on to this context. Can anyone help me how can i do that? I am confused about autofac here. Secondly how can i make sure each call sets connection string and does not cache it.
You can use a factory that will build the context and set the connectionstring for you.
public interface IContextFactory
{
IContext GetInstance();
}
public class MyContextFactory : IContextFactory
{
public IContext GetInstance()
{
String connectionString = this.GetConnectionString(HttpContext.Current);
return new MyContext(connectionString);
}
private String GetConnectionString(HttpContext context)
{
// do what you want
}
}
builder.RegisterType<MyContextFactory>()
.As<IContextFactory>()
.InstancePerRequest();
builder.Register(c => c.Resolve<IContextFactory>().GetInstance())
.As<IContext>()
.InstancePerRequest();
If you can't get connectionstring based on HttpContext, you can change contextFactory implementation to expect initialization by WebAPI before creating the instance. For example :
public interface IContextFactory
{
IContext GetInstance();
void Initialize(String connectionString);
}
public class MyContextFactory : IContextFactory
{
private String _connectionString;
public void Initialize(String connectionString)
{
this._connectionString = connectionString;
}
public IContext GetInstance()
{
if (this._connectionString == null)
{
throw new Exception("connectionString not initialized");
}
return new MyContext(this._connectionString);
}
}
At the beginning of your web API call (through attribute for example), you can call the Initialize method. Because the factory is InstancePerRequest you will have one instance for the duration of the request.
By the way, I'm not sure to understand this registration
builder.RegisterType(typeof(MainContext)).As(typeof(DbContext)).InstancePerLifetimeScope();
builder.RegisterType<MainContext>().As<IMainContext>().InstancePerRequest();
It looks buggy because you will have 2 different registration of the same type and not for the same scope, is it intended ? Furthermore, it doesn't sound a good idea to register a DbContext, do you need this registration ?
The following registration looks better :
builder.RegisterType<MainContext>()
.As<IMainContext>()
.As<DbContext>()
.InstancePerRequest();

dapper with autofac and repository pattern

I am using dapper with the repository pattern in a WebApi Application and I have the following problem.
The Repository Class is as follows
public class Repository : DataConnection, IRepository
{
public Repository(IDbConnection connection)
: base(connection)
{
}
public T GetFirst<T>(object filters) where T : new()
{
//Creates the sql generator
var sqlGenerator = new MicroOrm.Pocos.SqlGenerator.SqlGenerator<T>();
//Creates the query
var query = sqlGenerator.GetSelect(filters);
//Execute the query
return Connection.Query<T>(query, filters).FirstOrDefault();
}
The IRepository Interface has only one method, the GetFirst. A Controller that uses this repository is as follows
public class UsersController : ApiController
{
private IRepository Repository;
public UsersController(IRepository repository)
{
Repository = repository;
}
public User Get(int id)
{
return Repository.GetFirst<User>(new { id });
}
}
I use autofac as DI and in the Application_Start method in Global.asax I use the following code
string connString = ConfigurationManager.ConnectionStrings["DapperDemo"].ConnectionString;
SqlConnection connnection = new SqlConnection(connString);
var builder = new ContainerBuilder();
builder.RegisterType<Repository>().As<IRepository>();
builder.RegisterType<UsersController>().InstancePerRequest();
var container = builder.Build();
var resolver = new AutofacWebApiDependencyResolver(container);
GlobalConfiguration.Configuration.DependencyResolver = resolver;
But it seems that I am missing something cause I get the following error:
An error occurred when trying to create a controller of type 'UsersController'. Make sure that the controller has a parameterless public constructor.
You need to overwrite default controller activator, because it has no knowledge of your DI container.
Add a service class:
public class ServiceActivator : IHttpControllerActivator
{
public ServiceActivator(HttpConfiguration configuration) { }
public IHttpController Create(HttpRequestMessage request
, HttpControllerDescriptor controllerDescriptor, Type controllerType)
{
var controller = ObjectFactory.GetInstance(controllerType) as IHttpController;
return controller;
}
}
Then on Application_Start():
GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator), new ServiceActivator(GlobalConfiguration.Configuration));
I'm using structure map in this example, so just replace it with which ever container you are using.

MongoDB C# Driver database.GetCollection and magic strings

Just getting into the NoSQL stuff so forgive me if this is a simple question. I am trying to somewhat implement a repository type pattern using a generic repository for the more common operations.
One thing that I have run into that is killing this idea is that in order to get the collection you plan to work with you have to pass a string value for the name of the collection.
var collection = database.GetCollection<Entity>("entities");
This means that I have to hard code my collection names or code up a dictionary somewhere to act as a lookup so that i can map the object type to a collection name.
How is everyone else handling this?
What you can do is "semi-hardcode." You can put the name of the collection in a class name and refere to it:
public class Entity {
public static readonly string Name = "entities";
}
var collection = database.GetCollection<Entity>(Entity.Name);
I wrote a class to manage DB transactions
First you need a base class for all entities:
public abstract class Entity
{
public ObjectId Id { set; get; }
}
then an static class to manage all:
public static class MongoDB
{
private static string connectionString = "mongodb://localhost";
public static string DatabaseName { get { return "test"; } }
private static MongoServer _server;
private static MongoDatabase _database;
public static MongoServer Server
{
get
{
if (_server == null)
{
var client = new MongoClient(connectionString);
_server = client.GetServer();
}
return _server;
}
}
public static MongoDatabase DB
{
get
{
if(_database == null)
_database = Server.GetDatabase(MongoDB.DatabaseName);
return _database;
}
}
public static MongoCollection<T> GetCollection<T>() where T : Entity
{
return DB.GetCollection<T>(typeof(T).FullName);
}
public static List<T> GetEntityList<T>() where T : Entity
{
var collection = MongoDB.DB.GetCollection<T>(typeof(T).FullName);
return collection.FindAll().ToList<T>();
}
public static void InsertEntity<T>(T entity) where T : Entity
{
GetCollection<T>().Save(entity);
}
}
then use it like this:
public class SomeEntity : Entity { public string Name {set;get;} }
MongoDB.InsertEntity<SomeEntity>(new SomeEntity(){ Name = "ashkan" });
List<SomeEntity> someEntities = MongoDB.GetEntityList<SomeEntity>();
I finally found an approach very usefull for me as all my mongo collections follow a camel case underscore naming convention, so I made a simple string extension to translate the POCO naming convention to my mongo convention.
private readonly IMongoDatabase _db;
public IMongoCollection<TCollection> GetCollection<TCollection>() =>
_db.GetCollection<TCollection>(typeof(TCollection).ToString().MongifyToCollection());
This method is inside a class made for handling mongo using dependency injection and it also wraps the default GetCollection to make it a bit more OO
public class MongoContext : IMongoContext
{
private readonly IMongoDatabase _db;
public MongoContext()
{
var connectionString = MongoUrl.Create(ConfigurationManager.ConnectionStrings["mongo"].ConnectionString);
var client = new MongoClient(connectionString);
_db = client.GetDatabase(connectionString.DatabaseName);
RegisterConventions();
}
public IMongoCollection<TCollection> GetCollection<TCollection>() =>
_db.GetCollection<TCollection>(typeof(TCollection).Name.MongifyToCollection());
...
And the extension:
// It may require some improvements, but enough simple for my needs at the moment
public static string MongifyToCollection(this string source)
{
var result = source.Mongify().Pluralize(); //simple extension to replace upper letters to lower, etc
return result;
}

Is the Entity Framework 4 "Unit of Work" pattern the way to go for generic repositories?

I am looking into creating an Entity Framework 4 generic repository for a new ASP.NET MVC project i am working on. I have been looking at various tutorials and they all seem to use the Unit of Work pattern ...
From what i have been reading, EF is using this already within the ObjectContext and you are simply extending this to make your own Units of Work.
Source: http://dotnet.dzone.com/news/using-unit-work-pattern-entity?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+zones%2Fdotnet+(.NET+Zone)
Why would one go to the effort of doing this?
Is this the preferred way of working with generic repositories?
Many thanks,
Kohan.
This is not the way I would work with generic repositories. First of all, I would share ObjectContext between ClassARepository, CalssBRepository and other repositories in current request. Using IOC container, using injection and per request behavior is recommended:
This is how my generic repositories look like:
public interface IRepository<T>
{
//Retrieves list of items in table
IQueryable<T> List();
IQueryable<T> List(params string[] includes);
//Creates from detached item
void Create(T item);
void Delete(int id);
T Get(int id);
T Get(int id, params string[] includes);
void SaveChanges();
}
public class Repository<T> : IRepository<T> where T : EntityObject
{
private ObjectContext _ctx;
public Repository(ObjectContext ctx)
{
_ctx = ctx;
}
private static string EntitySetName
{
get
{
return String.Format(#"{0}Set", typeof(T).Name);
}
}
private ObjectQuery<T> ObjectQueryList()
{
var list = _ctx.CreateQuery<T>(EntitySetName);
return list;
}
#region IRepository<T> Members
public IQueryable<T> List()
{
return ObjectQueryList().OrderBy(#"it.ID").AsQueryable();
}
public IQueryable<T> List(params string[] includes)
{
var list = ObjectQueryList();
foreach(string include in includes)
{
list = list.Include(include);
}
return list;
}
public void Create(T item)
{
_ctx.AddObject(EntitySetName, item);
}
public void Delete(int id)
{
var item = Get(id);
_ctx.DeleteObject(item);
}
public T Get(int id)
{
var list = ObjectQueryList();
return list.Where("ID = #0", id).First();
}
public T Get(int id, params string[] includes)
{
var list = List(includes);
return list.Where("ID = #0", id).First();
}
public void SaveChanges()
{
_ctx.SaveChanges();
}
#endregion
}
ObjectContext is injected through constructor. List() methods return IQueryable for further processing in business layer (service) objects. Service layer returns List or IEnumerable, so there is no deferred execution in views.
This code was created using EF1. EF4 version can be a little different and simpler.