I wonder if anyone out there can help me with the following problem...
I have a created a EF code first database (sqlexpress) that uses Identity v2 -I can see within that database all my models, including the Identity related tables starting with Identity* (ie. IdentityUserClaims, IdentityUserLogins, IdentityUserRoles IdentityRoles & IdentityUsers).
I then create a brand new MVC project as well as adding the same connection string. When I register a new user -for some reason it goes off and creates Identity v2 tables starting with AspNet* (ie. AspNetUserClaims, AspNetUserLogins, AspNetUserRoles AspNetRoles & AspNetUsers).
[I am using... EF 6.1.1, Identity 2.1, MVC 5.2]
Why does the Identity naming schema differ between EF and AspNet ? how do I make MVC use the EF schema Identity* ?
You can override table names by [Table("MyUsers")] attribute on top of your classes:
[Table("WhateverILikeUsers")]
public class ApplicationUser : IdentityUser
{
}
Or you can rename tables in DbContext:
public class MyContext : IdentityDbContext<ApplicationUser>
{
// other stuff
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<ApplicationUser>().ToTable("HelloIdentity");
}
}
Related
I am working with an existing system and updating it to .NET Core, Web API and EF Core.
The existing system has 2 tables:
Parent table: Id, name, etc..
Child table: Id, ParentId, name, etc..
Though ParentId exists in the child table, there is no foreign key reference, but I want to be able to use include when I query the parent. I have asked not to add FK as part of deleting they are putting -ve values to parentId column. This way they can bring it back and a legacy system was built that way.
Now, in db-first migration how can I specify a navigation property without fk so my EF Core to act relational; or at least return them together. Adding nullable foreign key is not an option as it will break the system when -ve values are added.
I do have suggested for full cleanup of DB and getting rid of -ve values but that involves lots of testing and no deliverable. So long story short how to add navigation property without foreign key in database first migration ?
I tried adding collection and virtual entry in the model, but after migration it got overwritten. I have added this by using HasMany on modelbuilder as per this document - https://learn.microsoft.com/en-us/ef/core/modeling/relationships?tabs=fluent-api%2Cfluent-api-simple-key%2Csimple-key
But scaffolding is overriding my navigation property
I found out the answer for this.
In EF core 3.x the dbcontext created by DBFrist scaffolding is all partial classes.
So I did the following:
1. new partial class for context class - here i added the relationship of navigation property using OnModelCreatingPartial() method. Example below
public partial class dbContext : DbContext
{
partial void OnModelCreatingPartial(ModelBuilder builder)
{
builder.Entity<Packcomponent>()
.HasOne(p => p.Pack)
.WithMany(b => b.PackComponent)
.HasForeignKey(p => p.PackId);
}
}
extended the partial class in a new file and added navigation property there.
public partial class Packcomponent
{
public Pack Pack { get; set; }
}
public partial class Pack
{
public List PackComponent { get; set; }
}
This way upon scaffolding it did not overwrite custom navigation properties and I also could use this properties to do EF operations like .Include() and to save related entities as well. It is pretty awesome!!
I've setup a .net core api app to host JWT token authentication using an asp identity database. That part works great. My problem is when I go to add custom classes, every migration I perform is trying to create the AspNet* tables again even though they exist. The migration is aware of my custom class (Test) and wants to create it, but the script it's trying to run dies on the AspNetRoles table (already exists error).
I create a new migration:
Add-Migration NewMigration
Then update:
Update-Database
Here is my ApplicationDBContext.cs:
public class ApplicationDBContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDBContext(DbContextOptions<ApplicationDBContext> options) : base(options)
{
}
// This is my custom class
public DbSet<Test> Test { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
}
}
I'm at a loss. I just need to do migrations and have EF Core ignore the AspNet identity tables.
Edit: Here is ApplicationUser.cs
public class ApplicationUser : IdentityUser
{
}
Migrations folder:
I have built the following model of hierarchy for DB:
public abstract class ApplicationUser : IdentityUser
{ }
public class FirstUser : ApplicationUser
{}
public class SecondUser : ApplicationUser
It is noticeable abstract Application class inherits from ASP.NET Core Identity's not abstarct class IdentityUser.
So my purpose is building different tables for UserFirst and UserSecond only, not for IdentityUser and ApplicationUser.
I tried to configure model the following:
builder.Ignore<IdentityUser>();
builder.Entity<FirstUser>().ToTable("FirstUsers");
builder.Entity<SecondUser>().ToTable("SecondUsers");
However it throws exception: Invalid column name 'Discriminator'
What can I do?
Table per Concrete Type (TPC) or Table per Type (TPT) aren't currently supported in EntityFrameework Core 1.0. Only Table per Hierarchy (TPH) is supported.
TPC and TPT are on the high priority list and may come in EntityFramewor Core 1.1 or 1.2, see the EntityFramework Core Roadmap.
Backlog Features
...
High priority features
...
Modelling
More flexible property mapping, such as constructor parameters, get/set methods, property bags, etc.
Visualizing a model to see a graphical representation of the code-based model.
Simple type conversions such as string => xml.
Spatial data types such as SQL Server's geography & geometry.
Many-to-many relationships without join entity. You can already model a many-to-many relationship with a join entity.
Alternate inheritance mapping patterns for relational databases, such as table per type (TPT) and table per concrete type TPC.
As for your question:
You can't do anything about it. If you absoloutely need this feature, you have to fall back to EntityFramework 6.x, but then you can't target .NET Core and have to target .NET Framework 4.x.
It should be noted here, that Microsoft do not feels (or recommends) to use EntityFramework Core 1.0 yet in production environment, if you require the features used from EF6. It will take several versions (at least 2 minor releases) until EntityFramework Core will get anyway close featurewise to EF6.
So if TPC is absolute requirement, go back to EF6.
Technical stuff aside, performance wise it's prefered to use TPH for mapping inheritance to your database as it avoids unnecessary joins during queries. When you use TPT/TPC every query invovling it will have to perform joins and joins are less performant.
So unless you have to map to a legacy DB designed in that way, you should fall back to TPH.
Table-per-concrete-type (TPC) mapping is now available in EFC 7.0.0 nightly builds.
https://github.com/dotnet/efcore/issues/3170
https://github.com/dotnet/efcore/issues/3170#issuecomment-1124607226
https://learn.microsoft.com/en-gb/ef/core/what-is-new/ef-core-7.0/plan#table-per-concrete-type-tpc-mapping
What you need to try it out:
.NET SDK 7.0.100-preview.4
https://dotnet.microsoft.com/en-us/download/dotnet/7.0
Visual Studio 2022 Preview 17.3
https://visualstudio.microsoft.com/vs/preview/
NuGet
Microsoft.EntityFrameworkCore 7.0.0-preview.4.22229.2
Code example:
ApplicationDbContext:
using Microsoft.EntityFrameworkCore;
namespace WebApplicationNet7.Data
{
public class ApplicationDbContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<RssBlog> RssBlogs { get; set; }
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>().UseTpcMappingStrategy();
modelBuilder.Entity<RssBlog>().UseTpcMappingStrategy();
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
}
public class RssBlog : Blog
{
public string RssUrl { get; set; }
}
}
Migration will look like this:
Note that RssBlog is missing .Annotation("SqlServer:Identity", "1, 1").
You will probably get a warning that looks like this:
Microsoft.EntityFrameworkCore.Model.Validation[20609]
The property 'BlogId' on entity type 'Blog' is configured with a
database-generated default, however the entity type is mapped to the
database using table per concrete class strategy. Make sure that the
generated values are unique across all the tables, duplicated values
could result in errors or data corruption.
I could not get it to work with either setting
modelBuilder.Entity<RssBlog>().Property(u => u.BlogId).UseIdentityColumn(); or using annotation [DatabaseGenerated(DatabaseGeneratedOption.Identity)].
I am developing an Asp.Net mvc5 project. I am using Entity Framework code first approach to interact with the database. I am using Identity System for user authentication. But I am having a problem with integrating the AspNetUsers table from identity system to my model. My identity system database context and model database context class are different because I am using built in included identity system.
But connection string are same. Both use default connection string. But model is in different project. Now I am in the middle of the project. I have existing model classes mapped with tables in database. I created an user account from UI, so required tables(AspNetUsers table included) for identity system are auto-migrated. Now I want to create model class to map AspNetUsers table because I want to create relationship with between that AspNetUsers table and one of the existing tables. So I created a model class named "AspNetUser" class in my model project. Then I created properties for that class according to AspNetUsers table in database. Then I add migration and update database for my model. It gave me following error.
There is already an object named 'AspNetUsers' in the database.
What I can think is to delete AspNetUsers table and update database. But if I delete it, I have to delete other tables required for identity system because they have FK relationship. I do not want it. Second way I can think is to delete all required tables for identity system. Then migrate AspNetUser model class. Then delete that class and register new account from UI. So all required tables for identity system will be created again.
Second way also, I have to delete tables and happen data loss. How can I migrate overriding the existing AspNetUsers table? Is it possible? What is the best way to integrate AspNetUsers table to my model?
This is Configuration class in Migration folder
internal sealed class Configuration : DbMigrationsConfiguration<PatheinFashionStore.Domain.Concrete.StoreContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = true;
AutomaticMigrationDataLossAllowed = true;
}
protected override void Seed(PatheinFashionStore.Domain.Concrete.StoreContext context)
{
}
}
This is my context initializer class
public class ContextInitializer : System.Data.Entity.CreateDatabaseIfNotExists<StoreContext>
{
protected override void Seed(StoreContext context)
{
}
}
If it is not possible, what would be the best way?
This applies to EF 5 and database first modeling. My model was built useing the EF generator from an existing DB.
I'm using the [Key] data annotation in my model classes because the primary key fields have names that are not in line with EF conventions.
Everything works, but when I open the root EDMX files, the model classes are updated and any manual changes I had made are lost.
Should I be making my changes in a different manner?
You could update your T4 template to add in the data annotation for you on primary keys?
if (simpleProperties.Any())
{
foreach (var edmProperty in simpleProperties)
{
if (ef.IsKey(edmProperty)){
#>
[Key]
<# } #>
the solution that worked for me was to overide the EF convention in OnModelCreating method in the context class.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<abk_Bookings>()
.HasKey(e => e.booking_number);}