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.
Related
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();
I'm trying to implement UoW and Repository pattern, but I get error
An entity object cannot be referenced by multiple instances of IEntityChangeTracker.
I know that I get that error because I have two repositories which create two different DBContext, but I don't know why that happens.
Here is my code for UoW
public class UnitOfWorkRepositoryRepository : IUnitOfWorkRepository
{
private readonly IDatabaseFactory _databaseFactory;
private DatabaseContext _databaseContext;
public UnitOfWorkRepositoryRepository(IDatabaseFactory databaseFactory)
{
_databaseFactory = databaseFactory;
}
public DatabaseContext Database
{
get { return _databaseContext ?? (_databaseContext = _databaseFactory.GetDatabaseContext()); }
}
public void Save()
{
_databaseContext.Save();
}
}
And here sample Repository:
private static readonly DatabaseFactory DatabaseFactory = new DatabaseFactory();
private static readonly UnitOfWorkRepositoryRepository UnitOfWorkRepositoryRepository = new UnitOfWorkRepositoryRepository(DatabaseFactory);
public User GetUserById(int id)
{
return UnitOfWorkRepositoryRepository.Database.Users.SingleOrDefault(u => u.UserId.Equals(id));
}
What's wrong ? how should I implement UoW
P.S.
I'm not getting any errors in this repository, but other one was too long, this one serves just as sample.
Did you try this
http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application
I think it is more descriptive, I have ever seen.
Have a look at this SO answer where I describe a way to decoulple Uow from Repository.
I have a code like this:
public abstract class DataContextBase
{
public DbContext DbContext { get; protected internal set; }
public ObjectContext ObjectContext { get; protected internal set; }
protected DbTransaction transaction;
protected void SetContext(DbContext db, ObjectContext oc)
{
DbContext = db;
ObjectContext = oc;
}
public void BeginTransaction()
{
if (ObjectContext.Connection.State != System.Data.ConnectionState.Open)
{
ObjectContext.Connection.Open();
}
transaction = ObjectContext.Connection.BeginTransaction();
}
public void CommitTransaction()
{
try
{
transaction.Commit();
}
finally
{
transaction = null;
ObjectContext.Connection.Close();
}
}
public void RollbackTransaction()
{
try
{
transaction.Rollback();
}
finally
{
transaction = null;
ObjectContext.Connection.Close();
}
}
public void Save()
{
DbContext.SaveChanges();
}
}
It is from a sample application, and I use this as a base class of my application's main data context. I'm using Entity Framework 5, and I have just read that when I call the DbContext's SaveChanges method, it always runs in a database transaction and it will throw an exception when the transaction have to be rollbacked and in this case the changes are not saved into the database.
But in the sample application, almost every service method begins with a DataContextBase.BeginTransaction call and ends with a DataContextBase.CommitTransaction call (in an exceptional case it ends with DataContextBase.RollbackTransaction) even though that DataContextBase.Save is called (which calls DbContext.SaveChanges()).
It looks like there is an extra transaction wrapping the built in transaction of the DbContext.SaveChanges call.
Could there be any situation which needs this extra transaction?
NOTE: The DataContextBase's ObjectContext is come from the DbContext with a trick:
((IObjectContextAdapter)this).ObjectContext; // inside the DbContext class
Having an extra transaction is redundant because ObjectContext/DbContext implements Unit of Work. If you have other means of communicating with the database and they also need to be part of the transaction the use TransactionScope.
Connection management is also done by EF and you do not have to
I am creating an ASP.NET MVC 3 e-commerce website and I am currently working on the admin area where you can add/edit products. To create the UI for the product page I am using Telerik MVC controls.
My problem is that when I added a second telerik grid which both retrieve data from the database through an ajax call I receive a couple different errors listed below:
{"There is already an open DataReader associated with this Command
which must be closed first."}
{"The connection was not closed. The connection's current state is
connecting."}
Database Context Code
public interface IUnitOfWork
{
void Commit();
}
public class GSPDataContext : DbContext, IUnitOfWork
{
/* (omitted) IDbSet's for entities */
public GSPDataContext()
: base("GSPConnectionString")
{
}
public virtual IDbSet<T> DbSet<T>() where T : class
{
return Set<T>();
}
public virtual void Commit()
{
base.SaveChanges();
}
}
Generic Repository Code
public class Repository<T> : IRepository<T> where T : class
{
private GSPDataContext m_dataContext;
private readonly IDbSet<T> m_entity;
public Repository(GSPDataContext dataContext)
{
if (dataContext == null)
throw new ArgumentException();
m_dataContext = dataContext;
m_entity = m_dataContext.Set<T>();
}
public T GetById(int id)
{
return this.m_entity.Find(id);
}
public void Insert(T entity)
{
if (entity == null)
throw new ArgumentException();
this.m_entity.Add(entity);
//this.m_dataContext.SaveChanges();
}
public void Delete(T entity)
{
if (entity == null)
throw new ArgumentException();
this.m_entity.Remove(entity);
//this.m_dataContext.SaveChanges();
}
public virtual IQueryable<T> Table
{
get
{
return this.m_entity;
}
}
}
Ninject Code
private static void RegisterServices(IKernel kernel)
{
//Customer
kernel.Bind<IAddressValidationService>().To<AddressValidationService>().InRequestScope();
kernel.Bind<ICustomerService>().To<CustomerService>().InRequestScope();
kernel.Bind<ICustomerProductService>().To<CustomerProductService>().InRequestScope();
//Authentication
kernel.Bind<IOpenIDLoginService>().To<OpenIDLoginService>().InRequestScope();
kernel.Bind<IAuthenticationService>().To<FormsAuthenticationService>().InRequestScope();
//Products
kernel.Bind<IProductService>().To<ProductService>().InRequestScope();
kernel.Bind<IRecentlyViewedProductService>().To<RecentlyViewedProductService>().InRequestScope();
kernel.Bind<IProductPictureService>().To<ProductPictureService>().InRequestScope();
kernel.Bind<ICategoryService>().To<CategoryService>().InRequestScope();
kernel.Bind<IPictureService>().To<PictureService>().InRequestScope();
//Shopping Cart
kernel.Bind<IShoppingCartService>().To<ShoppingCartService>().InRequestScope();
//Shipping and Payment
kernel.Bind<IShippingService>().To<ShippingService>().InRequestScope();
kernel.Bind<IPaymentService>().To<PaymentService>().InRequestScope();
//Orders
kernel.Bind<IOrderCalculationService>().To<OrderCalculationService>().InRequestScope();
kernel.Bind<IOrderProcessingService>().To<OrderProcessingService>().InRequestScope();
kernel.Bind<IOrderService>().To<OrderService>().InRequestScope();
//
kernel.Bind<IEncryptionService>().To<EncryptionService>().InRequestScope();
kernel.Bind<ILogger>().To<LoggingService>().InRequestScope();
kernel.Bind<IWebManager>().To<WebManager>().InRequestScope();
//Messages
kernel.Bind<IEmailService>().To<EmailService>().InRequestScope();
kernel.Bind<IMessageTemplateService>().To<MessageTemplateService>().InRequestScope();
kernel.Bind<IWorkflowMessageService>().To<WorkflowMessageService>().InRequestScope();
//Data
kernel.Bind<GSPDataContext>().ToSelf().InSingletonScope();
kernel.Bind<IUnitOfWork>().ToMethod(ctx => ctx.Kernel.Get<GSPDataContext>()).InSingletonScope();
kernel.Bind(typeof (IRepository<>)).To(typeof (Repository<>)).InRequestScope();
kernel.Bind<IWorkContext>().To<WebWorkContext>().InRequestScope();
}
I suspect it has something to do with how ninject is managing the lifetimes of the various services, but I am not sure what I need to do to make it work.
Any advice would be much appreciated.
Thanks
UPDATE
According to Remo's comment I change my code to the following:
//Data
kernel.Bind<GSPDataContext>().ToSelf().InRequestScope();
kernel.Bind<IUnitOfWork>().ToMethod(ctx => ctx.Kernel.Get<GSPDataContext>()).InRequestScope();
kernel.Bind(typeof (IRepository<>)).To(typeof (Repository<>)).InRequestScope();
And I am now getting the following error:
The ObjectContext instance has been disposed and can no longer be used
for operations that require a connection.
Any ideas?
No, it has nothing to do with how Ninject manages lifetimes. But it has to do how you configured the lifecycles.
It is important that a new DbContext is used for each request. This has to be InRequestScope.
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>()));