I want to implement repository pattern in my ASP.NET MVC project. I've seen a lot of implementations when searching google and I'm a little bit confused. Most of them created their own Context class which inherited from DBContext class and then injected it in a repository (or repositories) constructor.
None of the articles I found explain why the custom DBContext class is created and why they just don't use default ApplicationDbContext and HOW to change your app code to adapt to the new Context class. They don't even mention the class.
I'd rather use default ApplicationDbContext which I would inject in repository classes, because at the moment I don't see a point in creating a new DBContext class. Am I missing something? Is it a bad practice?
If, for some reason, I will have to add new DbContext class, how to edit my code (web.config and others) to adapt it? If I already made migrations to database, would change of DBContext class affect the database? Would it be necessary to do migrations once again?
To give you an example look at the MSDN documentation:
https://learn.microsoft.com/en-us/aspnet/mvc/overview/older-versions/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application
I just have no idea why the author uses SchoolContext instead of ApplicationDbContext.
it's a broad question, a guess that's the reason for the down votes.
You do seem confused. First off, I'm not an expert (see points). I did get a little bit in the weeds with the default ApplicationDbContext. Maybe you use a template where it pops up? Anyway, I launched the MVC-template and tehre's no default context class provided.
In short you create your own Context-class. You give it any name you want, given that in ends with Context AND IT INHERITS from DbContext. If not the Entity framework will not recognise it, and will not know what to do with it when building the database an so on. See your article:
The main class that coordinates Entity Framework functionality for a given data model is the database context class. You create this class by deriving from the System.Data.Entity.DbContext class. In your code you specify which entities are included in the data model. You can also customize certain Entity Framework behavior. In this project, the class is named SchoolContext.
Blockquote
By default you have only one Context-class.
It is self evident you need to create your own context-class, since you can't access the DbContext-class. (And even if you could, you should not want to do that, you need to separate the abstract and the implemented.)
I don't understand §2. ApplicationDbContext is just a way to write MySelfNamedContextClass.
§3: I don't know if working with two contect-classes is possible/feasible, but the simple implication is that you would be working with two separate databases. That's already pretty complicated, and what you're wrtiting about is not heading in that direction.
If I already made migrations to database, would change of DBContext
class affect the database? Would it be necessary to do migrations once
again?
Yes, absolutely it would. Your adding a table or a field or a constraint or a relationship to it ... .
You can do two things depending on the changes you bring:
(i) add a supplemental migration
(ii) You would have to rewind your migrations (remove-migration). It could be that you need to reset your db to your first migration (update-database 'here name of first migration without the quotation marks'. If you get stuck with that, and you're still on local db, just remove db by deleting it outright (maybe after closing solution) and rewind and rebuild the migrations and rebuild the database.
Especially for scenario (ii), if you have already data in the database (that isn't seeded into it), you would need to take measures to store it somewhere !!!
I hope this somehow answers your questions.
Kind regards.
Related
I'm using EF Core and have generated the database with migration (code first). In the meantime I have created a View in DB directly and would like to reverse engineer this views in my dbcontext file. I know I can follow this link to get the view but I don't know if this can mess up my existing dbContext class or not.
Is there a recommendation that you only need to use migrations or reverse engineering, or can you mix them depending on the use case you have.
I've always used one or the other, but having the reverse engineering feature in such a case would be great, but I'm not sure if this is a good idea.
Thanks
I would recommend you to not mix these two things. With reverse engineering, you will get a generated DB context class file, but with the code first approach, you are manually writing the context file.
Why do you want to use reverse engineering? If you want to create the entity classes for the views from the DB, you can use it, but in my opinion this is not so comfortable (you should only keep the changes that are related to the views and drop everything else).
I'm trying to use EF 4.3 migrations with multiple code-first DbContexts. My application is separated into several plugins, which possibly have their own DbContext regarding their domain. The application should use one single sql-database.
When I try to auto migrate the contexts in an empty database, this is only successful for the first context. Every other context needs the AutomaticMigrationDataLossAllowed-Property set to true but then tries to drop the tables of the previous one.
So my question is:
How can I tell the migration-configuration just to look after the tables defined in their corresponding context and leave all others alone?
What is the right workflow to deal with multiple DbContexts with auto-migration in a single database?
Thank you!
Here is what you can do. very simple.
You can create Configration Class for each of your context.
e.g
internal sealed class Configuration1 : DbMigrationsConfiguration<Context1>{
public Configuration1 (){
AutomaticMigrationsEnabled = false;
MigrationsNamespace = "YourProject.Models.ContextNamespace1";
}
}
internal sealed class Configuration2 : DbMigrationsConfiguration<Context2>{
public Configuration2 (){
AutomaticMigrationsEnabled = false;
MigrationsNamespace = "YourProject.Models.ContextNamespace2";
}
}
Now you add migration. You dont need to enable migration since you already did with the 2 classed above.
Add-Migration -configuration Configuration1 Context1Init
This will create migration script for context1. your can repeat this again for other Contexts.
Add-Migration -configuration Configuration2 Context2Init
To Update your database
Update-Database -configuration Configuration1
Update-Database -configuration Configuration2
This can be done in any order. Except you need to make sure each configration is called in sequence.
Code First Migrations assumes that there is only one migrations configuration per database (and one context per configuration).
I can think of two possible solutions:
Create an aggregate context that includes all the entities of each context and reference this "super" context from your migrations configuration class. This way all the tables will be created in the user's database, but data will only be in the ones that they've installed plugins for.
Use separate databases for each context. If you have shared entities between the contexts, add a custom migration and replace the CreateTable(...) call with a Sql("CREATE VIEW ...") call to get the data from the entity's "originating" database.
I would try #1 since it keeps everything in a single database. You could create a seperate project in your solution to contain your migrations and this "super" context. Just add the project, reference all of your plugins' projects, create a context that includes all of the entities, then call Enable-Migrations on this new project. Things should work as expected after that.
I have a working site with multiple contexts using migrations. However, you do need to use a separate database per context, and it's all driven off of a *Configuration class in the Migrations namespace of your project, so for example CompanyDbContext points to Company.sdf using CompanyConfiguration. update-database -configurationtypename CompanyConfiguration. Another LogDbContext points to Log.sdf using LogConfiguration, etc.
Given this works, have you tried creating 2 contexts pointing at the same database and telling the modelbuilder to ignore the other context's list of tables?
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Ignore<OtherContextsClass>();
// more of these
}
Since the migrations work with the ModelBuilder, this might do the job.
The crappy alternative is to avoid using Automatic Migrations, generate a migration each time and then manually sift through and remove unwanted statements, then run them, although there's nothing stopping you from creating a simple tool that looks at the Contexts and generated statements and does the migration fixups for you.
Ok, I have been struggling with this for a day now, and here is solution for those seeking the answer...
I am assuming that most people reading this post are here because they have a large DbContext class with a lot of DbSet<> properties and it takes a long time to load. You probably thought to yourself, gee, that makes sense, I should split up the context, since I won't be using all of the dbsets at once, and I will only load a "Partial" context based on the situation where I need it. So you split them up, only to find out that Code First migrations don't support your way of revolutionary thinking.
So your first step must have been splitting up the contexts, then you added the MigrationConfiguration class for each of the new contexts, you added the connection strings named exactly the same as your new Context classes.
Then you tried running the newly split up contexts one by one, by doing Add-Migration Context1 then doing Update-Database -Verbose...
Everything seemed to work fine, but then you notice that every subsequent Migration deleted all tables from the Previous migration, and only left the tables in from the very last migration.
This is because, the current Migrations model expects Single DbContext per Database, and it has to be a mirror match.
What I also tried, and someone suggested here doing that, is create a single SuperContext, which has All the Db sets in it. Create a single Migration Configuration class and run that in. Leave your partial Context classes in place, and try to Instantiate and use them. The EF complains that the Backing model has changed. Again, this is because the EF compares your partial dbcontext to the All-Sets context signature that was left over from your Super Context migration.
This is a major flaw in my opinion.
In my case, I decided that PERFORMANCE is more important than migrations. So, what I ended up doing, is after I ran in the Super context and had all the tables in place, I went into the database and Manually deleted _MigrationHistory table.
Now, I can instantiate and use my Partial Contexts without EF complaining about it. It doesn't find the MigrationHistory table and just moves on, allowing me to have a "Partial" view of the database.
The trade off of course is that any changes to the model will have to be manually propagated to the database, so be careful.
It worked for me though.
As mentioned above by Brice, the most practical solution is to have 1 super DbContext per application/database.
Having to use only 1 DbContext for an entire application seems to be a crucial technical and methodological disadvantage, cause it affects Modularity among other things. Also, if you are using WCF Data Services, you can only use 1 DataService per application since a DataService can map to only 1 DbContext. So this alters the architecture considerably.
On the plus side, a minor advantage is that all database-related migration code is centralized.
I just came across this problem and realised the reason I had split them into different contexts was purely to have grouping of related models in manageable chunks and not for any other technical reason. Instead I have declared my context as a partial class and now different code files with different models in them can add DbSets to the DbContext.
This way the automigration magic still works.
I've got it working with manual migrations, but you can't downgrade as it can't discrimitate between configurations in the __MigrationHistory table. If I try and downgrade then it treats the migrations from the other configurations as automatic and since I don't allow data loss it fails. We will only ever be using it to upgrade though so it works for our purposes.
It does seem like quite a bit ommision though, I'm sure it wouldn't be hard to support it provided there was no overlap between DbContexts.
Surely the solution should be a modification by the EntityFramework team to change the API to support the direct modification of the _MigrationHistory table to a table name of your choice like _MigrationHistory_Context1 such that it can handle the modification of independent DbContext entities. That way they're all treated separately, and its up to the developer to ensure that the names of entities don't collide.
Seems like there are a lot of people who share my opinion that a duplicate DbContext with references to the superset of entities is a bogus non-enterprise friendly way to go about things. Duplicate DbContexts fail miserably for modular (Prism or similar) based solutions.
I want people to know that the answer with this below is what worked for me but with one caveat: don't use the MigrationsNamespace line.
internal sealed class Configuration1 : DbMigrationsConfiguration<Context1>{
public Configuration1 (){
AutomaticMigrationsEnabled = false;
MigrationsNamespace = "YourProject.Models.ContextNamespace1";
}
}
internal sealed class Configuration2 : DbMigrationsConfiguration<Context2>{
public Configuration2 (){
AutomaticMigrationsEnabled = false;
MigrationsNamespace = "YourProject.Models.ContextNamespace2";
}
}
However, I already had the 2 databases established with their own contexts defined so I found myself getting an error saying "YourProject.Models namespace already has ContextNamespace1 defined". This was because the "MigrationsNamespace = "YourProject.Models.ContextNamespace2";" was causing the dbcontext to be defined under the YourProjects.Models namespace twice after I tried the Init (once in the migration Context1Init file and once where I had it defined before).
So, I found that what I had to do at that point was start my database and migrations from scratch (thankfully I did not have data I needed to keep) via following the directions here:
http://pawel.sawicz.eu/entity-framework-reseting-migrations/
Then I changed the code to NOT include the MigrationsNamespace line.
internal sealed class Configuration1 : DbMigrationsConfiguration<Context1>{
public Configuration1 (){
AutomaticMigrationsEnabled = false;
}
}
internal sealed class Configuration2 : DbMigrationsConfiguration<Context2>{
public Configuration2 (){
AutomaticMigrationsEnabled = false;
}
}
Then I ran the Add-Migration -configuration Configuration1 Context1Init command again and the Update-Database -configuration Configuration1 line again (for my 2nd context too), and finally, everything seems to be working great now.
I am currently writing a .NET MVC application using a SQL Server DB and Code First EF. All has been going great and stackoverflow has been extremely helpful. Unfortunately I have an issue I cannot solve and I can't find any help on the Internet.
I want to integrate with PayPal and I was following http://logcorner.com/asp-net-mvc-paypal-integration which seems fairly straight forward except that VS wants to create a database table for my PayPal model and I don't need or want it to. I have added [NotMapped] in front of the class but now it generates this error:
The type 'MyApp.Models.PayPal' was not mapped. Check that the type has not been explicitly excluded by using the Ignore method or NotMappedAttribute data annotation. Verify that the type was defined as a class, is not primitive or generic, and does not inherit from EntityObject.
I saw some other information about adding Ignore(lambda expression) in the OnModelCreating() method of my db context but that seems to be for excluding a column, not the entire class.
Any ideas? I don't want a database table for every model in my application.
By Default all the model will be created in database which is the part of your myAppEntities : DbContext class and which properties type is DbSet<>.If you have decorated your model MyApp.Models.PayPal as notmappedattribute.
[NotMapped]
public class PayPal
{
//your all properties
}
Then remove Dbset<PayPal> properties from your class which is inherited form DbContext Class.
public class MyAppEntities : DbContext
{
public DbSet<PayPal> paypal { get; set; } //Remove this or comment this line
...
...
//rest of your properties
}
By doing so this won't be part of your database and you wont get this error.
( Explanation of this thing will cover a whole topic which i can't explain here).
Your usage of the [NotMapped] attribute is correct offhand. The issue is either that (a) you're attempting to scaffold while this attribute is in force, or (b) you're attempting to access the db in relation to this type at run-time. That's when I saw this error during my test work (see later).
At the design end, the following would solve your problem if you are using auto-scaffolding (but see later):
Delete or comment out [NotMapped] on your PayPal-facing class.
Recompile. (Due to latencies in MVC's introspection into the code,
your past attribute will still be in force until you do this.)
Now do your scaffolding.
Now uncomment or re-add [NotMapped].
Recompile again for the same reason as before.
There isn't much reason to auto-scaffold if that is where you're having problems, as you don't want to save your data so you don't need CRUD ops. The example on your refsite uses nearly-empty controllers compared to what the IDE generates for you.
At the run-time end (that is, in your controller code), just make sure you never touch the db. Definitely nothing like db.SaveChanges(); You shouldn't need to as I was saying; this is really a ViewModel and it exists solely to push data to PayPal.
To verify the problem and solution, I created an example MVC app, got the message you saw, took the design-time steps, then ran the app in a browser, got the problem message again, removed the db-facing code from my unmapped-class controller, and was able to have things work properly. I didn't use the PayPal-facing class but a simpler one to save time, but there should be no difference in outcome.
I hope this resolves your problems. --Ed
Maybe an odd question, but we have a scenario in which we want to use Entity Framework code-first in an environment which could have a database with a newer/higher version than the code itself.
Let me elaborate a bit. We have a couple of solutions which all use a core assembly which contains the overall datamodel which all solutions are using. The solutions are mainly sites and apps which are deployed to several different Azure Web Sites. So the solution are running next to each other. The only thing they are sharing is the Azure database.
Now the scenario will come in play. When we update the database model in the core assembly and update one of the solutions in Azure. The underlying database will be updated when the model is loaded within that solution. No problem there, works like a charm...
The problem starts when one of the other solutions is loaded. These other solution are still using the previous core assembly which has now an outdated EF CF model compared to the database model they are connecting with. So a nice exception will be throw as shown below.
The model backing the '{NAME}' context has changed since the database was created. Either manually delete/update the database, or call Database.SetInitializer with an IDatabaseInitializer instance. For example, the DropCreateDatabaseIfModelChanges strategy will automatically delete and recreate the database, and optionally seed it with new data.
The question is whether we can force the model just to load and ignore the changes made within the database. We internally have a policy to only apply not breaking changes within the database, so the model should be able to load without any problems.
Thanks in advance for the information and tips!
I can be wrong(not sure whether I remember correctly), but if it doesn't interferes with your application configuration, you can set DB initializer to null:
public PortalDbContext()
: base("name=PortalConnectionString")
{
Database.SetInitializer<PortalDbContext>(null);
}
Or it could be possible to create custom initializer:
public class BlogContextCustomInitializer : IDatabaseInitializer<BlogContext>
{
public void InitializeDatabase(BlogContext context)
{
if (context.Database.Exists())
{
if (!context.Database.CompatibleWithModel(true))
{
// Do something...
}
}
}
}
If you're using EF Code-First, the model must match the database.
Even if you found a way to circumvent that limitation you'd be doing something dangerous.
Let me expalin it: if you update the database from "Solution A", the model in "A" will match the database, and any further changes to the model in this solution can be applied to the database without any problem at all. That's right!. However, if you do what you're asking in this question, i.e. you do something so that "Solution B" can keep working even if the model doesn't mathc with the DB, and then you make a change to the model in "Solution B", how do you apply it? how can "Solution B" know what changes to apply? how can "B" determine what changes made by "A" should be left as they are, and what are the new changes made by "B" that must be applied to the database?
If you could follow on like this, you'd finish with two different code first models, none of which matches the database, and, besides, how could you warranty that both applications work correctly? how can you ensure that changes on "A" doesn't affect code on "B" and viceversa?
The safest solution to avoid this problem is to share the assembly containing the code first model between both solutions. Any other solution will be troublesome sooner or later. Perhaps you'll have to refactor your solutions so that they can share the same DbContext. The DbContext must be the only thing in your project. I usually have an Entities project, and a DbContext project which has a reference to Entities. Then both solutions would have references to these projects. These projects can be in one of the solutions, or in a completely different solution. Of course in one, or both solutions, you'll have to add a reference to the DbContext assembly, instead of the project, and keep it updated, for which you can use post-build scripts. In this way, when you recompile your solutions you'll also detect incompatible changes made for one solution which adversely affects the other.
EF6 supports several different DbContexts in the same database, so, if each of your applications had a different, non conflicting DbContext, you wouldn't have a problem. I cannot check it right know, but I think that the name of the DbContext must be different in each solution (I don't remember if the namespaces are taken into account). By non conflicting I mean that they refer to different database objects (tables, views, or whichever), of that the objects refered to by both contexts are not changed (for example master tables).
I am learning the Entity Framework and using it in an MVVM app where each ViewModel works with the DbContext for Data Access. Disclaimer: In a real application I know the ViewModel shouldn't interact directly with the Data Access Layer.
Given that each ViewModel is there to monitor and manipulate the state of the View by maintaining relationships with the Models themselves, I began to wonder about the implications of spinning up multiple DbContext objects, and if something like a DBContext is best left as a singleton - to which I quickly found the answer was "NO". So if the consensus is to have an instance for each use (as in the case with multiple ViewModels, or what-have-you) I still havent seen where any one mentions the potential issues with having this.
To elaborate, lets say I have two ViewModels and in each I create a Context (TestContext inherits from DbContext) to maintain the Data Access activities during the lifetime of each ViewModel:
public class MainWindowViewModel : ViewModelBase
{
private TestContext db = new TestContext();
... other code follows (properties methods etc...)...
}
public class TestViewModel: ViewModelBase
{
private TestContext db = new TestContext();
... other code follows (properties methods etc...)...
}
Are there any pitfalls with having a context in each class that can consume it?
One such thought that taunts me is if it's possible to have either context be out of sync with the other, such that one ViewModel has more recent data than the other by way of its context being more "up-to-date". Things like this I am interested in knowing.
Thanks.
EDIT
I dont hope to discover / cover every situation as that would be unique TO the situation against which one is coding. I just want to know if there are any "up-front" or obvious perils that I am unaware of being new to the subject.
Entity Framework and by extension DbContext supports the UnitOfWork design pattern. The idea being that you keep your logical "transactions" separated. Because of this, you will usually want to have each portion or feature of your application deal with its own DbContext instance.
The way you can think about it is that the DbContext holds a local copy of whatever it pulled from the database and tracks all changes made to the local data by the user. When you're ready, you tell it to push the required changes back to the database in one go.
For your question about pit-falls and perils; The Entity Framework uses what's called optimistic concurrency by default. This means that when saving the local changes back to the database, concurrency isn't checked at all. Whatever you had in your local DbContext is sent back to the database regardless of whether another user or another context in your application changed it. An excellent article explaining that and how to change the behaviour can be found here:
http://msdn.microsoft.com/en-us/library/bb738618.aspx