OnModelCreating code refactoring from EF6 to EF core 3.1 - asp.net-core

I am trying to refactor the OnModelCreating method before when it used to be a part of ASP.net: :
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Types().Configure(c => c.ToTable(c.ClrType.Name.ToUpper()));
modelBuilder.Properties().Configure(c => c.HasColumnName(c.ClrPropertyInfo.Name.ToUpper()));
....
But now after migrating to .netCore 3.1 I am getting this error
'ModelBuilder' does not contain a definition for 'Types' and no accessible extension method 'Types' accepting a first argument of type 'ModelBuilder' could be found
Could you please suggest a way to refactor the code properly while keeping the same old logic
Thanks for your help

According to your code, it seems that you want to change the Table Name and set the Column Name, if that is the case, you could try to refer the following code to override the OnModelCreating method:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<Blog> Blogs { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
//Write Fluent API configurations here
//Property Configurations
modelBuilder.Entity<Blog>().ToTable("BLOGS");
modelBuilder.Entity<Blog>()
.Property(b => b.BlogId)
.HasColumnName("BLOG_ID");
}
}
More detail information, please check the following links:
EF Core Fluent API Configuration
Entity Types # Table Name
Column names
How to Specify Entity Framework Core Table Mapping?
Edit:
And what about the second config rule ;
modelBuilder.Properties().Configure(c =>
c.HasColumnName(c.ClrPropertyInfo.Name.ToUpper())); I cant go through
every column there to just make it uppercase
There have an open source plugin (Naming Conventions) which might help you. By using its UseUpperCaseNamingConvention, it could change the table and Column name to Uppercase.
You could refer to the following steps to use it:
Add the EFCore.NamingConventions from the Nuget.
Enable the naming convention in your model's OnConfiguring method:
public class SchoolContext : DbContext
{
public SchoolContext(DbContextOptions<SchoolContext> options) : base(options)
{
}
public DbSet<Customer> Customers { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
optionsBuilder.EnableSensitiveDataLogging();
optionsBuilder
.UseSqlServer("Server=(localdb)\\mssqllocaldb;Database=TestDB;Trusted_Connection=True;MultipleActiveResultSets=true") //database connection string.
.UseUpperCaseNamingConvention();
}
}
After migration, you can see the Model Snapshot, it will change the Table and Column name as below:
Then, after update the database, the table like this:
[Note] The Naming Conventions is a community-maintained plugin: it isn't an official part of Entity Framework Core and isn't supported by Microsoft in any way.

Related

How to add new colum into Identity RoleClaims table (asp net core)

I'm trying to add a column to the identity (asp net core) RoleClaims table but I find content just to extend the roles and users classes and not to RoleClaims.
Could someone help with examples or point out content.
You would need to create a new class to extend the RoleClaim. Here is an example of how to do it if your key type is string:
public class ApplicationRoleClaim : IdentityRoleClaim<string>
{
public virtual ApplicationRole Role { get; set; }
}
You can add whatever new properties you want to this class then create a migration to add them as table columns.
You would also need to tell your IdentityDbContext to use this new class as well. Here is an example from the docs:
public class ApplicationDbContext
: IdentityDbContext<
ApplicationUser, ApplicationRole, string,
ApplicationUserClaim, ApplicationUserRole, ApplicationUserLogin,
ApplicationRoleClaim, ApplicationUserToken>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
}
EDIT:
With your custom ApplicationRoleClaim class, you could override OnModelCreating as well. This is an example from the docs:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
⋮
modelBuilder.Entity<IdentityRoleClaim<string>>(b =>
{
b.ToTable("MyRoleClaims");
});
⋮
}
Reference: Identity model customization in ASP.NET Core
I made a demo with asp.net core 2.2 and it worked well ,try the following code , customize ApplicationRoleClaim to add other propertyies.
public class ApplicationRoleClaim: IdentityRoleClaim<string>
{
public string Description { get; set; }
}
Then use DbSet<TEntity> class which represents a collection for a given entity within the model and is the gateway to database operations against an entity to add the new column to table
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<ApplicationRoleClaim> ApplicationRoleClaim { get; set; }
}
Finally add-migration and update-database.

Entity Framework Core Issue - Update-Database Creating "User" Schemas

I've been working for quite a while on a production application using .NET Core 2.0 (originally 1.0) & EF Core.
This is a Code-First designed application, so all database changes have been made via Migrations.
Up until a recent deployment, Update-Database would make the changes correctly - however, recently it has been creating new schemas each time a model is added (instead of adding to the dbo schema like normal).
Example:
New Class Model: Test.cs
Table created in Database: DOMAIN\CurrentUser.Test
Any ideas on why this would be happening?
I suppose I can dig deep into the migrationBuilder to figure out how it is making Schema decisions, but seems like something simple must have changed to change the behavior.
"DOMAIN\CurrentUser" has dbo rights on the server in question.
For changing schema from EF Core, try to configure with builder.HasDefaultSchema("newschema"); or builder.Entity<User>().ToTable.
For changing the schema for all tables.
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<User> User { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.HasDefaultSchema("newschema");
}
}
For chaning the schema for specific table.
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<User> User { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<User>().ToTable("User", "newSchema");
}
}

No parameterless constructor defined for this object in asp.netcore migrations

I am new to ASP.NET Core. learning new version of .NET Core 2.0 using VS Code. I got stuck while doing creating database using migration. First, it gives an exception of implementation of IDesignTimeDbContextFactory. After solving this, it still gives an exception of
No parameterless constructor defined for this object
Here's my code for DbContextClass:
public VegaDbContext CreateDbContext(string[] args)
{
IConfigurationRoot configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.Build();
var builder = new DbContextOptionsBuilder<VegaDbContext>();
var connectionString =
configuration.GetConnectionString("DefaultConnection");
builder.UseSqlServer(connectionString);
return new VegaDbContext(builder.Options);
}
I had tried a couple of ways when I was experimenting with ef core. I faced similar issues too. Finally I found services working great. First you will need to create your DBContext with the following override constructor:
public VegaDbContext(DbContextOptions<VegaDbContext> options) : base(options)
{
}
In your start up, you can add your context as a service like this:
services.AddDbContext<ApplicationDBContext>(config => {
config.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
});
You can read in full detail about how dependency injection works here:
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection
This part should help you with the migration. You can perform your migrations using the dotnet ef commands https://learn.microsoft.com/en-us/ef/core/miscellaneous/cli/dotnet.
When using your db context, do ensure that you are using dependency injection so you make full use of the AddDbContext function and keep it DRY.
https://learn.microsoft.com/en-us/aspnet/core/data/ef-mvc/intro
If I were your in your shoes, I look at this document.
Here is the simple DbContext that you can find on this webSite
namespace ContosoUniversity.Data
{
public class SchoolContext : DbContext
{
public SchoolContext(DbContextOptions<SchoolContext> options) : base(options)
{
}
public DbSet<Course> Courses { get; set; }
public DbSet<Enrollment> Enrollments { get; set; }
public DbSet<Student> Students { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Course>().ToTable("Course");
modelBuilder.Entity<Enrollment>().ToTable("Enrollment");
modelBuilder.Entity<Student>().ToTable("Student");
}
}
}
I just got the same error. If you are careful the error description is actually giving you the solution of the problem.
  DesignTimeFactoryObject's constructor function should not take parameters.
public class ExampleDesignTimeFactory : IDesignTimeDbContextFactory<YourDBContext>{
public ExampleDesignTimeFactory(){ no constructor or no parameter constructor }
}
I use ASP.NET CORE 3.1 to create the project and it solved

How to implement IModelCacheKeyFactory in EF Core

The story: in our multi-tenant app (one PostgreSql db, multiple schemas) we need to use one DbContext against multiple schemas.
What I tried: holding a cache (Dictionary, where key is schema name, value is the context for that schema). When instatiating new context for another schema I can see that dbContext schema is still set to previous schema provided. I assume the model in context is cached internally by context type, so that is the reason I see this behavior?
So above doesn't seem to work and I found that implementing IModelCacheKeyFactory should do the trick. Does anyone know what should go into Create method though? There are no samples nor documentation anywhere.
What I found:
Dynamically changing schema in Entity Framework Core but it answers for EF6, so not much help.
Here is an example.
Derived DbContext that replaces it's ModelCacheKey (and factory) with a Custom one.
class MyDbContext : DbContext
{
public MyDbContext(string schema)
{
Schema = schema;
}
public string Schema { get; }
protected override void OnConfiguring(DbContextOptionsBuilder options)
=> options
.UseSqlServer("...")
.ReplaceService<IModelCacheKeyFactory, MyModelCacheKeyFactory>();
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasDefaultSchema(Schema);
// ...
}
}
The factory that creates the Context with a specific key.
class MyModelCacheKeyFactory : IModelCacheKeyFactory
{
public object Create(DbContext context)
=> new MyModelCacheKey(context);
}
The custom ModelCacheKey per context.
class MyModelCacheKey : ModelCacheKey
{
string _schema;
public MyModelCacheKey(DbContext context)
: base(context)
{
_schema = (context as MyDbContext)?.Schema;
}
protected override bool Equals(ModelCacheKey other)
=> base.Equals(other)
&& (other as MyModelCacheKey)?._schema == _schema;
public override int GetHashCode()
{
var hashCode = base.GetHashCode() * 397;
if (_schema != null)
{
hashCode ^= _schema.GetHashCode();
}
return hashCode;
}
}
There actually have demo project in docs https://github.com/aspnet/EntityFramework.Docs/tree/master/samples/core/DynamicModel adding post for convinience !

Entity Framework Code First without modelBuilder.Configuration or runtime modify modelBuilder.Configuration

I am new to Entity Framework and I have created class derived from DbContext with following example.
public partial class StudentdbContext : DbContext{
public StudentdbContext()
: base("Name=StudentdbContext"){
}
public DbSet<student> students { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder){
modelBuilder.Configurations.Add(new studentMap());
}
}
now runtime I am adding another entity called "StudentInfo" with code studentdbContext.Set<"StudentInfo">() , but how can I add "StudentInfoMap" to modelBuilder.Configuration runtime ? Is is possible to use Code First Entity Framework without map object such as "EntityTypeConfiguration" and "EntityTypeConfiguration" ?
thanks
You must either use a Configuration type, or define the mapping directly in the OnModelCreating method:
protected override void OnModelCreating(DbModelBuilder modelBuilder){
modelBuilder.Configurations.Add(new studentMap());
modelBuilder.Entity<StudentInfo>()
.HasRequired(...)
etc
}