Automatically updating database with multiple DbContexts - asp.net-mvc

I'm using EF6 in ASP.NET 5 project. Where I'm using ASP.NET Identity as the authentication mechanism. As anyone would do, I have modeled my domain objects in a separate dll project and for data access logic I have a separate project. This data project contains EF migrations, DbContext for domain models, repositories and Unit of work.
And I have a service layer which is contacted by ASP.NET controllers and this service layer will communicate with data layer and do required operations.
In the main ASP.NET web project I have the default DbContext which is related to Identity and it's migrations.
Having two DbContexts somehow prevents me from updating database automatically. If I had only one DbContext after I create migrations for model changes, it will automatically run on the first time I try to access the website. This doesn't happen anymore, always I have to run the "update-database" command manually.
One solution I have right now is to add a reference to "Microsoft.AspNet.Identity.EntityFramework" in my data project and use Identity context contain my domain tables. But adding an ASP.NET reference in my data project is something I don't want to do unless I have no other options. Because data layer is not even communicating directly with web layer.
Even though this video by Scott Allen discuss about this issue, a solution is not proposed.

You can kick in migrations explicitly by using database initializer and using MigrateDatabaseToLatestVersion. This initializer allows you explicitly state the context and configuration you want to use. Something like:
SetInitializer(new MigrateDatabaseToLatestVersion<MyContext, Configuration>());
You can also call all the logic manually, effectively doing the same as Update-Database cmdlet, when you want during app start. Look at DbMigrator class.

You can run migration inside each DbContext constructor separately.
public class DataContext: DbContext
{
static DaraContext()
{
Database.SetInitializer(new MigrateDatabaseToLatestVersion<DataContext, Configuration>());
}
}
public class ApplicationDbContext : IndetityDbContext
{
static ApplicationDbContext()
{
Database.SetInitializer(new MigrateDatabaseToLatestVersion<ApplicationDbContext, Configuration>());
}
}

Related

How to share a DbCOntext in n-tier repository pattern. Asp .net mvc

Firstly i must say, i know their is a very close question i found on stackoverflow, but my question is a little different.
I have n-tier application in asp .net mvc, in which I have: A BOL project(which has EF classes and db object etc), BLL project(which has buiseness logic), than we have DAL project(which has db interaction logic, and it uses EF dbcontext from BOL). And a main mvc project which ahs controllers and views etc.
Now, we are using repository pattern, we have many Repositories in BLL with their interfaces. And also we have many repositories in DAL which are without interfaces though. But all of those DAL repositories have one DbContext member in them, which is being created in their constructors, so each DAL repository is interacting with separate instance of DbContext which it has created.
And in our main mvc project, we have used ninject to inject BLL repositories in controllers constructors (in request scope). Now, the issue we are facing is, that each BLL repository has references to one or more DAL repositories, and each of those DAL repositories are using their own seperate DbCOntext. Which is wrong and bad, thats why i am looking for the way to share one DbCOntext in all DAL repositories, per request(No matter how many BLL repositories ninject injects in my controller, just make sure only one DbContext instance is being created and used per request). And dispose that context after each request.
One way i thought was to not create DBcontext in constructor of DAL repositories. But have some method call(say initiateDbContext) for that, than also add this method in BLL repositories, which do nothing but to call the smae method of their member DAL repositories. Call that method for one BLL repository in controller constructor, and than have a method to get and set db contexts in all other repositories from the first repository. But i know this is bad approach, firstly we are creating DbContext in controller, which should be in DAL only, secondly i am adding create, get and set DbCOntext methods in DAL as well as in BLL repositories, because i need to pass DbCOntext to BLL which will pass that to the DAL repositories it communicates with internally. And that's very bad.
That's why i am asking here for any good pattern to achieve "ONE DBCONTEXT PER REQUEST IN N-TIER WITH REPOSITORY PATTERN."
If you are using dependency injection, you should use it all the way, not only in the controllers.
That means, the DBContext should be injected into the Repositories, and Ninject should be configured to resolve your DBContext with per request lifetime.
Based on the answer from #atika i searched further and implemented what he suggested(using ninject/DI in whole application rather than just in one main project of mvc) and it solved the issue, i am posting this answer to add more details and some extra issues i faced and i got to spend time googling about further, so others might save some time.
Idea is to use dependency injection throughout the solution, no matter how many projects/tiers you have in it and no matter how many repositories you have got.
So, the issue comes to the point, that if we want to use ninject or any other DI for binding all dependencies from all tiers/projects, we should have reference to all of those tiers/projects in our main mvc project, so that we can bind the dependencies in NinjectWebCommons, but this will kill the whole purpose of n-tier architecture. We don't want to do that, we want our hierarchy to sustain, like in my case
MainMVCProject->BLL->DLL->DB
So, for this, i found a very helpful article Ninject with N-Tier MVC Application - Inject Object in Business Layer.(Their are also some other approaches, one is to make a project just for bindings and add use that project to bind all dependencies, but that sounds like over engineering and overkill)
Based on which i added the following class in my BLL tier/project(after installing ninject in this project and DAL project too), which has bindings for DLL classes.
using BLL.Repositories;
using BLL.RepositoryInterfaces;
using Ninject.Modules;
using Ninject.Web.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DAL;
using BOL;
namespace BLL
{
public class LayerBindings : NinjectModule
{
public override void Load()
{//add all references here like these
Bind<AdDb>().ToSelf().InRequestScope();
Bind<db_Entities>().ToSelf().InRequestScope().WithConstructorArgument("ConnectionString", BOL.CommonFunctionsBOL.ConnectionString);
}
}
}
Getting some help from howto-ninject-part-1-basics article, i managed to do many things with ninject, and used many of its features.
Now, you can see i added the bindings of DLL project in this class, which were not accessible in main mvc project. Now, i just need to load these bindings in main ninject.
Now, in NinjectWebCommons.cs file, i added following lines:
//old bindings of BLL and local project.
kernel.Bind<IUserRepository>().To<UserRepository>().InRequestScope();
//now here we bind other dependencies of DAL etc using class we added in BLL
var modules = new List<INinjectModule>
{
new BLL.LayerBindings()
};
kernel.Load(modules);
(In RegisterServices method, after local bindings and BLL objects bindings.)
After doing just this, ninject started working in all the projects and i just used constructor injection or on some places, property injections and all worked fine.
PS1: I also used property injection*(i read that this is not recommended to use property injections, use them only where you cant use constructor injections.)* for private properties and they had to be enabled with kernel.Settings.InjectNonPublic = true; line in "CreateKernel" method before returning the kernal.
Now my property injection is working for private properties too, like this:
[Ninject.Inject]
private SomeDALObject db { get; set; }
PS2: I also installed ninject.web.webapi nuget package for ninject to work with webapis, and also found this line to get an object anywhere from ninject.(I don't know if this is a good way or not, but it does return a fully constructed object which i used than. If any one can clarify or correct me if using this is right or not, that will be great.)
((TypeOfObjectYouWant)System.Web.Mvc.DependencyResolver.Current.GetService(typeof(TypeOfObjectYouWant))).DoSomething();
I hope this might help some people like me looking for proper guide on this issue.
You can write one BaseRepository and implement BaseRepository in all repository classes.
public class BaseRepository
{
public StudentEntities dbStudentEntity;
public BaseRepository()
{
dbStudentEntity = new StudentEntities();
}
}
DataRepository :
public class CurrencyData : BaseRepository,ICurrencyData
{
public List<Models.Currency> GetCurrencyList()
{
var objCurrencies = dbStudentEntity.Currencies.ToList();
List<Models.Currency> currencyList = new List<Models.Currency>();
foreach (var item in objCurrencies)
{
var model = new Models.Currency { CurrencyId = item.CurrencyId, Currency1 = item.Currency1,Code = item.Code,Symbol = item.Symbol,Country = item.Country };
currencyList.Add(model);
}
return currencyList;
}
}

You custom database IdentityDbContext

I was trying to develop an application and created my own database which then was reflected to an entity model using database first. So I now already have let's say myOwnDBContext.
Then I thaught it wuld be a nice idea to mix it with the classes generated by IdentityDbContext. But when i just changed the connection string in IdentityModel like this
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("myOwnDBConnectionString")
{
}
}
The tables were not generated as I would expect in myOwnDB but instead I received the following error.
The entity type ApplicationUser is not part of the model for the
current context.
Is there a way I can mix the defualt database of IdentityDbContext with my own databse?
I'm not sure if this can work without using EF migrations, but I do have it working with migrations. Specifically, two DbContext derived classes (one for custom entities, one derived from IdentityDbContext).
For the migrations I had to enable-migrations from the package manager console for both contexts and use the -MigrationsDirectory parameter to place the two sets of migrations into distinct folders (a new feature for EF6).
Then when running update-database the tables are created properly for each context. The update-database command will need a -ConfigurationTypeName parameter to specify the exact migration to use.

Entity Framework is trying to create a database, but its not what I want

I have a small asp.net mvc4 application (working fine in my local machine), that uses entity framework v4.1.0.0 with ADO.net DbContext Generator.(SQL Server 2008 r2)
I am adding newer versions of dlls required through the "Add Deployable Dependencies..." context menu in Visual Studio 2010.
I have a shared hosting with godaddy.com, I have uploaded the files to server and created the database, now here comes the problem.When I try to browse my site I get the following error:
CREATE DATABASE permission denied in database 'master'.
I looked this up around and found out that this error was caused by EF code first trying to create database.but i do not want EF code first to recreate the database, how do i turn off this automatic database creation altogether? I have no intentions of using the code-first feature whatsoever.
Please help.
put this code into the Application_Start() method of Global.asax or constructor on your DbContext class
Database.SetInitializer<MyContext>(null);
If you want to recreate database when POCO domains are changed, use following code instead of above
Database.SetInitializer<MyContext>(new DropCreateDatabaseIfModelChanges<MyContext>());
If you are using EF Migrations, this is what you set for it:
public sealed class DbConfiguration : DbMigrationsConfiguration<DatabaseContext>
{
public DbConfiguration()
{
AutomaticMigrationsEnabled = false;
}
}
But this doesn't answer the question on EF Code First itself. If the database already exists, then EF will not try to create it. So you just need to point it to an existing database. And to make sure the connection string name is the same as the name of the database context. If it is not, you need to provide it to it with some overrides:
public class DatabaseContext : DbContext
{
public DatabaseContext()
: base(ApplicationParameters.ConnectionStringName)
{
}
public DatabaseContext(string connectionStringName)
: base(connectionStringName)
{
}
}

Problem with WCF Data service exposing custom partial methods of EF4 model

I am exploring the idea of implementing a web service api using WCF Data Services and EF4. Realizing that some operations require complex business logic, I decided to create a partial class the same name as the main EF data context partial class and implement additional methods there to handle the more complex business logic. When the EF context object is used directly, the additional method shows up (via intellisense) and works properly. When the EF classes are exposed through a WCF Data Service and a Service Reference is created and consumed in another project, the new method does not show up in intellisense or in the generated Service.cs file (of course, I updated the reference and even deleted it and re-added it). The native data methods (i.e. context.AddObject() and context.AddToPeople()) work properly, but the new method isn't even available.
My EF classes look something like this:
namespace PeopleModel
{
//EF generated class
public partial class PeopleEntities : ObjectContext
{
//Constructors here
//Partial Methods here
//etc....
}
//Entity classes here
//My added partial class
public partial class PeopleEntities
{
public void AddPerson(Person person)
{
base.AddObject("People", person);
}
}
}
There's nothing special about the .svc file. The Reference.cs file containing the auto generated proxy classes do not have the new "AddPerson()" method.
My questions are:
1. Any idea why the web service doesn't see the added partial class, but when directly using the EF objects the method is there and works properly?
2. Is using a partial class with additional methods a good solution to the problem of handling complex business rules with an EF generated model?
I like the idea of letting the oData framework provide a querying mechanism on the exposed data objects and the fact that you can have a restful web service with some of the benefits of SOAP.
Service operations are only recognized if they are present on the class which derives from DataService. The WCF Data Service will not look into the context class for these. Also note that methods are not exposed by default, you need to attribute them with either WebGet or WebInvoke and allow access to them in your InitializeService implementation.
http://msdn.microsoft.com/en-us/library/cc668788.aspx

NHibernate: "failed to lazily initialize...", DDD approach

I'm trying to set up NHibernate in an ASP.NET MVC application using a DDD approach. However, I do get an error when trying to lazy load an objects related entity. Heres how I've structured my application:
Infrastructure layer:
Contains mapping files, repository implementations and a NHibernate bootstrapper to configure and build a session factory.
Heres a repository example:
public class CustomerRepository : ICustomerRepository
{
public Customer GetCustomerById(int customerId)
{
using (var session = NHibernateBootstrapper.OpenSession())
return session.Get<Customer>(customerId);
}
}
Domain layer:
Has simple POCO classes, repository and service interfaces
Application layer:
Contains Service implementations.
Heres a service example:
public class CustomerService : ICustomerService
{
private ICustomerRepository _repository;
public CustomerService(ICustomerRepository repository)
{
_repository = repository;
}
public Customer GetCustomerById(int customerId)
{
return _repository.GetCustomerById(customerId);
}
}
Presentation layer:
Contains the ASP.NET MVC application. And this is where I discovered my problem.
Using the MVC approach, I have a controller which, using the CustomerService service, gets a customer and displays the customer in a View (strongly typed). This customer has a related entity Contact, and when I try to access it in my View using Model.Contact, where Model is my Customer object, I get an LazyInitializationException.
I know why I get this. It's because the session used to retrieve the Customer in the CustomerRepository is dead by now. My problem is how I can fix this. I would like if I could avoid getting the related Contact entity for the Customer in my repository, because some views only need the Customer data, not the Contact data. If this is possible at all?
So to the question: is it possible to wait querying the database, until the presentation layer needs the related entity Contact?
I think that what I need is something like what this article describes. I just can't figure out how to implement it in infrastructure layer, or where should it be implemented?
Thanks in advance. Any help will be much appreciated!
As for session management it is common to use single session per request. You can see an example of implementation here. It is an open source project that were designed to setup new asp.net applications with the help of Nhibernate wery easy. source code can be founded here.
Hope it helps.
I also recommend Sharp Architecture.
Another approach, as well as suggestion, is to avoid passing entities to views. There're other problems with it except session management - business rules leaking into views, bloated/spagetti code in there, etc. Use ViewModel approach.
Another problem you'll get is storing your entities in Session. Once you try to get your Customer from Session["customer"] you'll get the same exception. There're several solutions to this, for example storing IDs, or adding repository methods to prevent lazy-loading of objects you're going to store in session - read NHibernate's SetFetchMode - which, of course, you can also use to pass entity to views. But as I said you better stick with ViewModel approach. Google for ViewModel, or refer to ASP.NET MVC In Action book, which uses samples of code from http://code.google.com/p/codecampserver/. Also read this, for example.
Are all your properties and methods in your Customer class marked virtual?
How are you opening and closing your session? I use an ActionFilterAttribute called TransactionPerRequest and decorate all my controllers with it.
Check out this for an implementation.

Resources