I have been at this for hours. I have an existing code base, working just fine.
Moved over to Asp.Net Core and the latest Structuremap and now I am having issue with my DbContext.
I get this error
The specified LINQ expression contains references to queries that are associated with different contexts
Seems as if SM is NOT creating a single DbContext per request. But I cannot figure out WHY?
Here is a snippet from the repository.
private readonly EntityContext _context;
protected readonly DbSet<T> _dbSet;
public Repository(EntityContext context)
{
_context = context;
_dbSet = _context.Set<T>();
}
Here is my multiple ways I have tried to register the context with SM.
public StructureMapRegistry()
{
var unique = new UniquePerRequestLifecycle();
For<DbContext>().LifecycleIs(unique).ContainerScoped().Use<EntityContext>().ContainerScoped();
For<EntityContext>().LifecycleIs(unique).ContainerScoped().Use<EntityContext>().ContainerScoped();
//ForConcreteType<EntityContext>().Configure.Transient();
//For<DbContext>().ContainerScoped().Use<EntityContext>();
// For<EntityContext>().Use(() => new EntityContext());
For<IUnitOfWork>().ContainerScoped().Use<UnitOfWork>();
For(typeof(IRepository<>)).Use(typeof(Repository<>));
}
I am trying to implement a Generic repository as described in
https://codingblast.com/entity-framework-core-generic-repository/
It seems the generic DbSet does not have implemention for method AsNoTracking( ), am i not using the correct syntax? How to fix this issue
public class BaseRepository<TEntity> : IGenericRepository<TEntity>
where TEntity : class
{
private readonly DbContext _dbContext;
public BaseRepository(DbContext dbContext)
{
_dbContext = dbContext;
}
public IQueryable<TEntity> GetAll()
{
return _dbContext.Set<TEntity>().AsNoTracking();
}
}
There is nothing to fix here.
AsNoTracking method only configures query in a way that once it gets enumerated it won't track changes on those entities.
This is useful when you are doing read only and will not do any editing in that procedure. It is done for speed and efficiency.
So the method has no functionality that can be Async.
You will use Async methods when enumerating query, like:
ToListAsync() or
SingleOrDefaultAsync()
I have added a database repository layer to my MVC application which does the CRUD. Sometimes my controllers need to call multiple db repositories and I do this by calling the db respitories I need. This in turn creates multiple db context objects. One for each repository. Should there be multiple db context objects or should I pass in a single db context to the repository object?
In your controller you should use one dbContext. Because When you try to update your model in db, you may get error. Because of different dbContext.
Check HERE
There should be only one, I highly recommend using Unit of Work pattern:
Here's a quick and simple example:
public interface IUoW : IDisposable
{
MyDbContext DbContext { get; set; }
void SaveChanges();
}
public class UoW : IUoW
{
public MyDbContext DbContext { get; set; }
public UoW()
{
DbContext = new MyDbContext();
}
public void SaveChanges()
{
DbContext.SaveChanges();
}
public void Dispose()
{
DbContext.Dispose();
}
}
You need to instantiate UoW once for each request and pass it to your repository:
public class MyRepository
{
private MyDbContext _context;
public MyRepository(IUoW uow)
{
_context = uow.MyDbContext;
}
// your crud methods
}
Of course it's just a very simple example of it and I've seen people implement this pattern in many different ways.
Based on other posts such as Entity Framework and DbContext - Object Tracking
it would appear the simplified DBContext interface doesnt expose the to set No tracking on basic queries.
A little blog showing how with Object context
http://blogs.microsoft.co.il/blogs/gilf/archive/2009/02/20/disabling-change-tracking-in-entity-framework.aspx
What is a good approach to loading results via the DbContext as not tracked?
How are the performance conscious doing this if using Dbcontext ?
ie have base GetList method I would like to improve for performance reasons.
public DbSet<T> EntityDbSet { get { return _context.Set<T>(); } }
public virtual IQueryable<T> GetList(Expression<Func<T, bool>> predicate)
{
return EntityDbSet.Where(predicate);
}
The AsNoTracking is an extension on IQueryable.
You can update your function above with:
public virtual IQueryable<T> GetList(Expression<Func<T, bool>> predicate)
{
return EntityDbSet.Where(predicate).AsNoTracking();
}
Why there is no IDbContext interface in the Entity Framework? Wouldn't it be easier to test things if there was an existing interface with methods like SaveChanges() etc. from which you could derive your custom database context interface?
public interface ICustomDbContext : IDbContext
{
// add entity set properties to existing set of methods in IDbContext
IDbSet<SomeEntity> SomeEntities { get; }
}
I see this IDbContext:
See this link And then you make a new partial class for your Entities Context With That interface.
public partial class YourModelEntities : DbContext, IDbContext
EDITED:
I edited this post, This Works for me.
My Context
namespace dao
{
public interface ContextI : IDisposable
{
DbSet<TEntity> Set<TEntity>() where TEntity : class;
DbSet Set(Type entityType);
int SaveChanges();
IEnumerable<DbEntityValidationResult> GetValidationErrors();
DbEntityEntry<TEntity> Entry<TEntity>(TEntity entity) where TEntity:class;
DbEntityEntry Entry(object entity);
string ConnectionString { get; set; }
bool AutoDetectChangedEnabled { get; set; }
void ExecuteSqlCommand(string p, params object[] o);
void ExecuteSqlCommand(string p);
}
}
YourModelEntities is your auto-generated partial class, and your need to create a new partial class with the same name, then add your new context interface, for this example is ContextI
NOTE: The interface hasn't implement all methods, because the methods are implemented in your auto-generate code.
namespace dao
{
public partial class YourModelEntities :DbContext, ContextI
{
public string ConnectionString
{
get
{
return this.Database.Connection.ConnectionString;
}
set
{
this.Database.Connection.ConnectionString = value;
}
}
bool AutoDetectChangedEnabled
{
get
{
return true;
}
set
{
throw new NotImplementedException();
}
}
public void ExecuteSqlCommand(string p,params object[] os)
{
this.Database.ExecuteSqlCommand(p, os);
}
public void ExecuteSqlCommand(string p)
{
this.Database.ExecuteSqlCommand(p);
}
bool ContextI.AutoDetectChangedEnabled
{
get
{
return this.Configuration.AutoDetectChangesEnabled;
}
set
{
this.Configuration.AutoDetectChangesEnabled = value;
}
}
}
}
I was thinking also about that, I assume you are going to use it for mocking DbContext. I find no reason for that, except that you will need to implement your own DbSet manually in your anyway for your mocked class (so will need to rewrite your own interface anyway).
Just create a mock DbContext extending your production DbContext overriding the methods that complicate testing. That way, any changes to the production DbContext are automatically reflected in the tests, save for the overridden methods. For any other classes that deal with persistence and take the DbContext just extend them as well passing in the extended mock DbContext.
namespace Test.Mocks
{
public sealed class MockDatabaseContext : MainProject.Persistence.Database.DatabaseContext
{
public MockDatabaseContext(ConfigurationWrapper config) : base(config)
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
var dbPath = "test.db";
optionsBuilder.UseSqlite($"Filename={dbPath}");
}
}
}
namespace Test.Mocks
{
public class MockInventoryFacade : InventoryFacade
{
public MockInventoryFacade(MockDatabaseContext databaseContext) : base(databaseContext)
{
}
}
}
There is no IDbContext because it would be useless, the only implementation of it would be the DbContext.
EF team is also going this way with IDbSet if you look at this design meeting note
For me, the real problem with EF when it comes to unit testing is the DbConnection in the DbContext, fortunately there is Effort a nice project on codeplex that starts to fill this.
Effort is a powerful tool that enables a convenient way to create automated tests for Entity Framework based applications.
It is basically an ADO.NET provider that executes all the data operations on a lightweight in-process main memory database instead of a traditional external database. It provides some intuitive helper methods too that make really easy to use this provider with existing ObjectContext or DbContext classes. A simple addition to existing code might be enough to create data driven tests that can run without the presence of the external database.
With this, you can leave your DbContext and DbSet as is and do your unit tests easily.
The only drawback with this is the difference between Linq providers where some unit tests may pass with effort and not with the real backend.
UPDATE with EF7
I still maintain that IDbContext would be useless and the problem comes from the DbConnection.
EF7 will not have an IDbContext either, in order to do unit testing they are now giving an in memory provider.
You can see Rowan Miller doing a demo here: Modern Data Applications with Entity Framework 7