Forcing EF 6 to create tables with model first - c#

Currently I have a nice model, and I can generate a database based on that, but from what I can tell, the tables are never created (leading to all sorts of fun runtime errors).
My understanding is that there are three options for code first that would force EF to create the tables for me:
DropCreateDatabaseAlways
CreateDatabaseIfNotExists
DropCreateDatabaseIfModelChanges
How can I use these if I am doing things model first?
Additionally, is this an expected error, or when I selected generate database from model the first time is this supposed to happen automatically?
Edit: I tried calling
context.Database.Initialize(true);
context.Database.CreateIfNotExists();
and nothing changes.

also this is good toturial
tutorial
but if you made the model good the first time you access the dbContext the db should be created by the db strategy which you can set: Database.SetInitializer()
set initializer
in short after you create your model you need to create class that inherit from DbContext:
public class CompanyContext : DbContext
{
public CompanyContext() : base("CompanyDatabase") { }
public DbSet<Collaborator> Collaborators { get; set; }
public DbSet<Department> Departments { get; set; }
public DbSet<Manager> Managers { get; set; }
}
and then when you access this context the tables should be generated.
you can also seed the database with data you should inherit from the strategy you want to implement look at this link seeding database

Related

C# Entity Framework Adding New Column to Entity that's from external library

On a project I am working on I am having some troubles trying to add properties to an entity from an external NuGet package.
The external team originally used the EntityFramework to create their database, and awhile back my team used it initially in order to create ours, now having two separate databases but initial creation used the common NuGet package.
On the external team's side, they haven't changed the table at at all, but on our side we've added new columns and properties to our database and now we need it within our DBContext. How do I map these new fields to an Entity so that I can access and set the properties. I hoped it was protected but since it is public I can't just overwrite the DbSet<Profile> Profile call.
External Package:
DataContext (Class that extends DBContext and has a public DbSet<Profile> Profile {get;set;})
Profile (Entity that is mapped to the "Profile" table in the database)
Since I can't modify the Profile class, how do I go about adding new columns that are there in the table?
My initial approach was to create:
DataContextExt (class that extends DataContext and added public DbSet<ProfileExt> ProfileExt {get;set;}
ProfileExt (Entity that extends Profile and has the additional fields that aren't part of the original
This seems to get me the furthest, but since ProfileExt extends Profile, I get an error when using it due to the "Discriminator" column since they are both the same entity technically.
I then tried to remove Profile by overriding the OnModelCreating() and map my ProfileExt to Profile but that failed as well, it didn't seem to change the model builder at all.
public class DataContextExt : DataContext
{
public DbSet<ProfileExt> ProfileExt { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Ignore<Profile>();
modelBuilder.Entity<ProfileExt>().ToTable("Profile");
Database.SetInitializer<ApplicationDbContext>(null);
}
}
Does anyone have any suggestions on what I should try next going forward?
EDIT:
Currently the project is design to access the information VIA a Stored Procedure and then I mapped that to my ProfileExt, but when it comes to saving it is designed to use
Entity = await DB.Set<TModel>().FindAsync(Key.Compile()(Model)).ConfigureAwait(false);
Model is instance of ProfileExt when it reaches this point
If I try to pass a ProfileExt through(without its own DbSet) as Profile it fails saying ProfileExt is not in the context, and if I do register it (with its own DbSet) it throws the Discriminator error since once is an instance of another.
From the sounds of things you are using a library and initial schema provided by some third party. You don't share code modifications with that team but you've gone and changed part of their schema in your copy of this Profile table.
Why not keep the two DbContexts completely separate rather than trying to inherit to override?
One option would be not to add columns to a table/entity that you do not have ownership of to extend. Move your custom columns to something like a MasterProfile table which shares a ProfileId as it's PK. From there you can declare a MasterProfile entity with a one-to-one relationship with Profile.
public class MasterProfile
{
[Key]
public int ProfileId { get; set; }
// add custom columns here...
public virtual Profile Profile { get; set; }
}
then configure relationship:
modelBuilder.Entity<MasterProfile>()
.HasRquired(x => x.Profile)
.WithOptional();
This way you can read your custom object in your DbContext along with Profile without a breaking change to the schema.
Another option you could explore is to define your own Profile entity definition for your DbContext while reusing the other entity declarations from the 3rd party.
For example: Given a 3rd party library which defines the following classes:
3rdParty.User
3rdParty.Profile
3rdParty.TableA
3rdParty.TableB
3rdParty.TableC
and they are accessed by a 3rdParty.DataContext
I can define a MyApp.DataContext that does not need to extend 3rdParty.DataContext. That DbContext can reference a Profiles collection that is declared as:
MyApp.Profile
which contains the full set properties from our Profile table. Provided you don't have to worry about references to 3rdParty.Profile you don't need to create custom entities for every table, you can reference 3rdParty.TableA etc. in your MyApp.DataContext.
I.e.
public class DataContext : DbContext
{
public DbSet<Profile> Profiles { get; set; }
public DbSet<3rdParty.TableA> TableAs { get; set; }
public DbSet<3rdParty.TableB> TableBs { get; set; }
public DbSet<3rdParty.TableC> TableCs { get; set; }
}
The catch would be that this will only work if the class you define is not referenced by many other entities. Every 3rdParty entity definition we include in our DbContext can no longer reference a 3rdParty.Profile since our DbContext cannot have two entities mapped to the same table.
For instance, if Profile references a User, that isn't a problem since MyApp.Profile can reference 3rdParty.User, however if 3rdParty.User has a reference back like:
public virtual ICollection<Profiles> { get; set; }
which will be pointing back to the Profile in the 3rdParty assembly, this is a deal breaker. We will need to recreate a MyApp.User as well. This could cascade if something like User needs to be re-declared and that class is referenced by the majority of other entities. (I.e. public virtual User CreatedBy { get; set; })
It may be an option worth exploring.

Entity Framework 6 throws exception for missing SQL table not required by DbContext

I have created a DbContext, similar to the one below
public class ProductsDB : DbContext
{
public virtual DbSet<Product> Products { get; set; }
//..other stuff..
}
Here's Product;
[Table("product")]
public class Product
{
[Column("Product_ID")]
public int ID { get; set; }
//other fields...
}
This all works fine until I create a class that inherits from "Product";
[Table("CentralProducts")]
public class CentralProduct : Product
{
//fields...
}
When I run integration tests I get an error that states that dbo.CentralProducts doesn't exist. It doesn't, and for the database that ProductsDB is connecting to I don't want it to.
I have tried the various inheritance options but they either require the addition of a table to my database, or the addition of a discriminator column to the Product table.
I had hoped that since my context doesn't consume CentralProducts it would not require it to exist. I was using table-per-type inheritance so there shouldn't be any need for something consuming dbo.Product to be able to access dbo.CentralProduct. Is there a way to configure EF6 to allow for this?
The reason I am trying to do this is that I have two databases, each with a common set of tables. I would like to create two DbContexts, one for each database, each containing the core entities but also including a few differences. In this particular case, the second DbContext has a Product table that includes an additional field, hence my attempt at inheritance to solve the problem.

MVC / Entity Code-First Multiple Contexts with Referential Integrity between them

I'm having some difficulty getting my two contexts that use the same database to cooperate. Here's the scenario:
In an MVC application using EF 6 Code-First, there is one database with two contexts.
- The first context is the ApplicationIdentity context with a customized ApplicationUser object.
- The second context is the business context, which holds a Team model:
public class Team
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public ApplicationUser TeamLeader { get; set; }
public string Name { get; set; }
public virtual ICollection<ApplicationUser> TeamMembers { get; set; }
public bool IsActive { get; set; }
}
Managing the migrations has been difficult, though this answer has proven extremely helpful: Multiple DB Contexts in the Same DB and Application in EF 6 and Code First Migrations
The problem is that the Identity context keeps trying to create the Team table in it's migrations, and then the Business context keeps trying to create duplicate ApplicationUser records when a new team is created, populated, and saved.
What I would like is for the following rules to be applied:
The IdentityContext is responsible for creating and altering the schema of the Identity tables only. It has no knowledge of objects (aka Team) outside of it's area of responsibility.
The Business Context is responsible for referential integrity between it's objects and the IdentityObjects, but it may not edit records in the Identity tables. If a user does not exist, error, don't create.
Does anyone have any tips on how to get these contexts to play nice with each other? I really don't want to break the referential integrity between Identity objects and business objects.
What you're trying to do looks like "DDD Bounded Contexts".
It's a bit long to explain how to use them, but here are some tips:
use modelBuilder.Ignore<EntityType>(); to exclude from your model related entities that are automatically added to your context
use different classes in each model where necessary, and map them appropriately. I mean classes that map only part of the columns. Use modelBuilder to configure them
use readonly navigation properties and readonly properties where necessary
This is a very interesting post by Julie Lerman: Data Points - Shrink EF Models with DDD Bounded Contexts

Adding ViewModel class adds codefirst model to database

I need a view-model in my ASP.NET MVC 5 project, but when I added one to the models folder, a new entity was added to the database and I was forced to add a migration and update my database. I do not want this to happen, as it is a view-model I am adding and not a model I need to persist back to the database. I want to scaffold some of the controller and views so I have added a primary key to the class. I did not add the newly created view-model to my DbContext class.
ViewModel:
public class RolesViewModel
{
public int RolesViewModelId { get; set; }
public string Role { get; set; }
}
Is there a way to create a view-model that doesn't automatically get added to the DbContext class, and therefore cause the data model to change?
Many thanks,
Jason.
Whether you call it a view model, an entity, etc. it's just semantics. Everything is just a class, and the context it's used in determines what you refer to it as. In the case of entities, that's adding a reference either explicitly or implicitly in your DbContext, and that's the only way you'll end up with something added to your database. I emphasized the "or implicitly* part because if any class that is referenced in the your DbContext, or any class connected to any class referenced there, also references your "view model", it will end up in your database. Entity Framework will automatically follow your class hierarchies and create tables for all relationships, even if you do not reference a particular class in those hierarchies directly in your DbContext.
In your case Scaffolding will add the following code below in your appContext Class
public DbSet<RolesViewModel> RolesViewModel { get; set; }
You can still use scaffolding if you wish, however remember to remove that entry and no table will be created by code first. It will keep your database clean.

One Context class, two Model classes

I'm learning MVC, and I understand how to create a single model class, and then a single context class, and then create a controller and a view based on the model/context combination, and commit the model to a database using code-first.
Now I want to bring a second Model (and therefore table) into the mix. I initially tried creating a second context class, and then a second model class, and then a controller and a view in the same way. As a result of this I found out that I could only commit one model to the database at a time. Whenever I enabled automatic migration on one model, and then ran the Update-Database command in the package manager, the other table disappeared from my database, and the add/remove/edit/view functionality for the other model broke.
Surely you must be able to use this techinque to manage more than one table? My question is, if I have two model classes like below:
[Table("TableOne")]
public class ModelOne
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
public string Foo { get; set; }
}
[Table("TableTwo")]
public class ModelTwo
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
public string Bar { get; set; }
}
What does my Context class need to look like if I want to work with both? My idea was to try this:
public class FooBar : DbContext
{
public FooBar()
: base("DefaultConnection")
{
}
public DbSet<ModelOne> TableOne { get; set; }
public DbSet<ModelTwo> TableTwo { get; set; }
}
Then in the Add Controller wizard, I could select MVC controller with read/write actions and views, using Entity Framework from the Template drop-down list, ModelOne from the Model class drop-down list, and FooBar from the Data context class drop-down list for the first model, and the same options only with ModelTwo in the Model class drop-down list for the second model and everything would work as expected, but whenever I try to create the first controller based on model one, I get this error:
There was an error generating FooBar. Try rebuilding your project.
I have tried rebuilding my project, and I get the same error, so obviously I am doing something greater wrong. What am I doing wrong and how do I need to amend my FooBar context class to get things to work, assuming it is my FooBar context class which is wrong?
Generally, you won't have a 1-to-1 between context classes and model classes. All your associated models all go into one context. I generally have one context per area in my app, for instance, but if you aren't using areas, you can still group models logically in a single context.
Where the problem comes in is in having multiple contexts. EF only likes to migrate one context. Without migrations, you can pretty easily get all the context classes to use the same DB by specifying it manually on the context class.
public class MyContext: DbContext
{
public MyContext()
: base("name=MyConnectionName")
{
}
}
If each context is defined like that, they will all use the same DB the named connection string points to.
As far as getting migrations to play along, Julie Lerman, the author of Programming Entity Framework: DbContext (and pretty much all the relevant EF books out there), has a solution utilizing a generic base class (edit: actually Julie attributes the pattern to Arthur Vickers of the EF team):
public class BaseContext<TContext> : DbContext
where TContext : DbContext
{
static BaseContext()
{
Database.SetInitializer<TContext>(null);
}
protected BaseContext()
: base("name=breakaway")
{
}
}
And, then you have each individual context inherit from BaseContext:
public class TripPlanningContext : BaseContext<TripPlanningContext>
public class SalesContext : BaseContext<SalesContext>
The relevant section starts on page 231 of the aforementioned book.
UPDATE
Actually I lied to you. The pattern Julie gives is simply to make it easier to have them all share the same DB. To get past the migrations for only one context issue, you have to cheat and essentially create one big context with everything in it that you then use only for database initialization/migration. For everything else in your code, you would use your other more specific contexts.

Categories

Resources