I have just added GraphDiff in an existing Entity Framework solution which is utilizing Moq framework for testing.
All my tests that are using Moq in insert and update methods are now failing since method _context.UpdateGraph throws following exception: System.NullReferenceException: Object reference not set to an instance of an object.
GraphDiff on GitHub
https://github.com/refactorthis/GraphDiff
UpdateGraph extension method:
https://github.com/refactorthis/GraphDiff/blob/develop/GraphDiff/GraphDiff/DbContextExtensions.cs
How should you hookup Moq with GraphDiff?
We had this problem as well. This is how we solved it.
So this is in the IContext interface:
T UpdateGraph<T>(T entity, Expression<Func<IUpdateConfiguration<T>, object>> mapping = null) where T : class, new();
DbEntityEntry<TEntity> Entry<TEntity>(TEntity entity) where TEntity : class;
DbEntityEntry Entry(object entity);
DbContextConfiguration Configuration { get; }
This is in the base context:
public virtual T UpdateGraph<T>(T entity, Expression<Func<IUpdateConfiguration<T>, object>> mapping = null) where T : class, new()
{
return null;
}
and
private ObjectContext ObjectContext
{
get { return (this as IObjectContextAdapter).ObjectContext; }
}
And this is in the actual concrete context:
public override T UpdateGraph<T>(T entity, Expression<Func<IUpdateConfiguration<T>, object>> mapping = null) // where T : class, new()
{
return DbContextExtensions.UpdateGraph<T>(this, entity, mapping);
}
and
private ObjectContext ObjectContext
{
get { return (this as IObjectContextAdapter).ObjectContext; }
}
Related
I encapsulate the DbContext class in my DbContextBase class.
And something about delegating problem.
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling;
public abstract class DbContextBase : DbContext
{
public Task<int> ExecuteSaveChangesAsync()
{
return this.ExecuteAsync(base.SaveChangesAsync);
}
private Task<TResult> ExecuteAsync<TResult>(Func<Task<TResult>> taskFunc)
{
return this.retryPolicy.ExecuteAsync(taskFunc);
}
}
the SaveChangesAsync function is the virtual method at the DbContext clsss (EF Core)
public virtual Task<int> SaveChangesAsync(CancellationToken cancellationToken = default (CancellationToken));
I got the error :
Error CS0411 The type arguments for method
'DbContextBase.ExecuteAsync(Func>)' cannot be
inferred from the usage. Try specifying the type arguments explicitly.
I have no idea about it. Anyone help?
usage:
public Task<int> SaveOrUpdateAsync<T>(T entity, Expression<Func<T, bool>> identifierExpression) where T : class
{
EntityEntry<T> entry = this.Entry(entity);
if (entry.State == EntityState.Detached)
this.Set<T>().Add(entity);
if (this.Set<T>().Any(identifierExpression))
{
entry.State = EntityState.Modified;
}
return this.ExecuteSaveChangesAsync();
}
So the problem I am trying to solve is this; We are using Entity Framework to access our Oracle database that has 1200-1500 tables. Now mind you we are not accessing them all, but possibly could have 800+ to access. We are using the UnitOfWork --> Repository --> Service pattern and that works great, but we are trying to figure out if we should have one big DbContext, or multiple little contexts that are specific to the task at hand.
Our UnitOfWork is setup using an EFUnitOfWorkBase like so:
public abstract class EFUnitOfWorkBase : IUnitOfWork
{
private bool isDisposed = false;
public DbContextBase Context { get; set; }
protected EFUnitOfWorkBase(DbContextBase context)
{
Context = context;
}
public int Commit()
{
return Context.SaveChanges();
}
public void Dispose()
{
if (!isDisposed)
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
isDisposed = true;
if (disposing)
{
if (this.Context != null)
this.Context.Dispose();
}
}
public IRepository<TEntity> GetRepository<TEntity>() where TEntity : Common.EntityBase<TEntity>
{
return new Repository<TEntity>(this);
}
}
Any unit of work we create extends that base one and provides the context like so:
public class EmployeeDirectoryUnitOfWork : EFUnitOfWorkBase
{
public EmployeeDirectoryUnitOfWork(string connectionString)
: base(new EmployeeDirectoryContext(connectionString))
{
}
}
The DbContext is passed a connection string through the unit of work.
The Repository looks like this:
public abstract class RepositoryBase<TEntity> : IRepository<TEntity> where TEntity : class
{
protected DbContextBase Context;
protected DbSet<TEntity> EntitySet;
public RepositoryBase(EFUnitOfWorkBase unitOfWork)
{
Enforce.ArgumentNotNull(unitOfWork, "unitOfWork");
Context = unitOfWork.Context;
EntitySet = Context.Set<TEntity>();
}
public TEntity Add(TEntity entity)
{
Enforce.ArgumentNotNull(entity, "entity");
return EntitySet.Add(entity);
}
public TEntity Attach(TEntity entity)
{
Enforce.ArgumentNotNull(entity, "entity");
return EntitySet.Attach(entity);
}
public TEntity Delete(TEntity entity)
{
Enforce.ArgumentNotNull(entity, "entity");
return EntitySet.Remove(entity);
}
public System.Linq.IQueryable<TEntity> Query()
{
return EntitySet.AsQueryable();
}
public TEntity Save(TEntity entity)
{
Enforce.ArgumentNotNull(entity, "entity");
Attach(entity);
Context.MarkModified(entity);
return entity;
}
}
Any suggestions on how to best handle this situation?
In such a case when you have a large application like this, I think you should probably go for a more Domain Driven Design approach and split the contexts into some separate, bounded contexts. This way when later developers are adding features to the program they will be confined to only being able to access certain tables depending on which context they will be using there.
For better information, Julie Lerman recently came out with a course on Pluralsight about Entity Framework in the Enterprise that's really good. She posted a small clip of it (actually about bounded contexts) on this site. It's a very good course, and I highly recommend it, especially for what you appear to be doing.
I have been trying to work with Entity Framework's Code First. I wrote the below line of code
DbContext _context = new DbContext(ConfigurationManager.ConnectionStrings["con"].ConnectionString);
However on execution, the connection remains closed. Is there something wrong with this code??
I have created a generic repository class using the DBContext shown below
public class GenericRepository<T> where T:class
{
public DbContext _context = new DbContext(ConfigurationManager.ConnectionStrings["con"].ConnectionString);
private DbSet<T> _dbset;
public DbSet<T> Dbset
{
set { _dbset = _context.Set<T>(); }
get { return _dbset; }
}
public IQueryable<T> GetAll()
{
return Dbset;
}
}
and I then call this class on the page load event, where Teacher is an entity class which maps to a table in the database
protected void Page_Load(object sender, EventArgs e)
{
GenericRepository<Teacher> studentrepository = new GenericRepository<Teacher>();
rptSchoolData.DataSource = studentrepository.GetAll().ToList();
rptSchoolData.DataBind();
}
but the connection remains closed and there is also an InvalidOperation Exception in the ServerVersion of the context object.
Am I missing something??
This property
public DbSet<T> Dbset
{
set { _dbset = _context.Set<T>(); }
get { return _dbset; }
}
has a heavy smell to it. A setter that does nothing with value is an anti pattern big time. Do you expect to set the DbSet after creating a GenericRepository?
I don't understand that your code even works because you never initialize _dbset, it should throw a null object reference exception.
The _dbset and DbSet shouldn't be there in the first place. GetAll should return _context.Set<T>(). EF should open and close the connection all by itself. Maybe the fact that you don't initialize the DbSet causes a connection never to open, causing problems in other pieces of code not revealed here.
Here's the thing.
I have an interface, and I would to put the Include extension method, who belongs to EntityFramework library, to my IRepository layer wich dont needs to knows about EntityFramework.
public interface IRepository<TEntity>
{
IQueryable<TEntity> Entities { get; }
TEntity GetById(long id);
TEntity Insert(TEntity entity);
void Update(TEntity entity);
void Delete(TEntity entity);
void Delete(long id);
}
So I have the extension method:
public static class IncludeExtension
{
static IQueryable<TEntity> Include<TEntity>(this IQueryable<TEntity> query,
string path)
{
throw new NotImplementedException();
}
}
But I don't know how to implement it in this layer, and I would to send it to my EntityFramework (or whatever who will implement the IRepository) to deal with.
I need same to a Interface with a extension method.
Any light?
Include is leaky abstraction and it works only with Entity framework. EF 4.1 already contains Include over generic IQueryable but it internally only converts passed generic IQueryable to generic ObjectQuery or DbQuery and calls their Include.
Here is some example how to wrap that include in repository (repository implementation is dependent on EF so it can use Include provided by EF directly).
This question is a bit old, but here are two EF-independent solutions if you or anyone else is still looking:
1. Reflection-based Solution
This solution is what the .NET Framework falls back to if the IQueryable does not cast to a DbQuery or ObjectQuery. Skip these casts (and the efficiency it provides) and you've decoupled the solution from Entity Framework.
public static class IncludeExtension
{
private static T QueryInclude<T>(T query, string path)
{
MethodInfo includeMethod = query.GetType().GetMethod("Include", new Type[] { typeof(string) });
if ((includeMethod != null) && typeof(T).IsAssignableFrom(includeMethod.ReturnType))
{
return (T)includeMethod.Invoke(query, new object[] { path });
}
return query;
}
public static IQueryable<T> Include<T>(this IQueryable<T> query, string path) where T : class
{
return QueryInclude(query, path);
}
// Add other Include overloads.
}
2. Dyanmics-based Solution
Here the QueryInclude<T> method uses the dynamic type to avoid reflection.
public static class IncludeExtension
{
private static T QueryInclude<T>(T query, string path)
{
dynamic querytWithIncludeMethod = query as dynamic;
try
{
return (T)querytWithIncludeMethod.Include(path);
}
catch (RuntimeBinderException)
{
return query;
}
}
public static IQueryable<T> Include<T>(this IQueryable<T> query, string path) where T : class
{
return QueryInclude(query, path);
}
// Add other Include overloads.
}
In Entity Framework 5.0 they now provide an extension method to IQueryable to add the Include functionality. You will just need to add a using "System.Data.Entity" in order to resolve the extension method. For direct documentation go here
Following on the heels of my other question about mocking DbContext.Set I've got another question about mocking EF Code First.
I now have a method for my update that looks like:
if (entity == null)
throw new ArgumentNullException("entity");
Context.GetIDbSet<T>().Attach(entity);
Context.Entry(entity).State = EntityState.Modified;
Context.CommitChanges();
return entity;
Context is an interface of my own DbContext.
The problem I'm running in to is, how do I handle the
Context.Entry(entity).State.
I've stepped through this code and it works when I have a real live DbContext as the implementation of my Context interface. But when I put my fake context there, I don't know how to handle it.
There is no constructor for a DbEntityEntry class, so I can't just create a new one in my fake context.
Has anyone had any success with either mocking or faking DbEntityEntry in your CodeFirst solutions?
Or is there a better way to handle the state changes?
Just like the other case, what you need is to add an additional level of indirection:
interface ISalesContext
{
IDbSet<T> GetIDbSet<T>();
void SetModified(object entity)
}
class SalesContext : DbContext, ISalesContext
{
public IDbSet<T> GetIDbSet<T>()
{
return Set<T>();
}
public void SetModified(object entity)
{
Entry(entity).State = EntityState.Modified;
}
}
So, instead of calling the implementation, you just call SetModified.
Found this question when I needed to unit test with Moq, no need for your own interface. I wanted to set specific fields to not modified but the method SetModified can be used with object as well.
DbContext:
public class AppDbContext : DbContext
{
...
public virtual void SetModified(GuidEntityBase entity)
{
Entry(entity).State = EntityState.Modified;
Entry(entity).Property(x => x.CreatedDate).IsModified = false;
Entry(entity).Property(x => x.CreatedBy).IsModified = false;
}
...
}
Test:
var mockContext = new Mock<AppDbContext>();
mockContext.Setup(c => c.MyDbSet).Returns(mockMyDbSet.Object);
mockContext.Setup(c => c.SetModified(It.IsAny<GuidEntityBase>()));