更改IdentityServer4实体框架表名称

编程入门 行业动态 更新时间:2024-10-23 18:22:38
本文介绍了更改IdentityServer4实体框架表名称的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

我试图更改由PersistedGrantDb和ConfigurationDb为IdentityServer4创建的默认表名,并让Entity Framework生成正确的SQL.例如;而不是使用表 ApiResources 使用实体 IdentityServer4.EntityFramework.Entities.ApiResource ,我希望将数据映射到名为 mytesttable

I am trying to change the default table names created by the PersistedGrantDb and ConfigurationDb for IdentityServer4 and have Entity Framework generate the correct SQL. For example; instead of the using the entity IdentityServer4.EntityFramework.Entities.ApiResource using the table ApiResources, I want the data to be mapped into a table named mytesttable

根据文档,该文档应为就像为我要在 DBContext的 OnModelCreating 方法中重新映射的每个实体添加 ToTable 调用一样简单,以覆盖TableName = EntityName的默认行为.问题在于,这确实创建了一个表 mytesttable ,但是在运行时由Entity Framework创建的SQL仍然在查询中使用 ApiResources ,因此失败.

According to the documentation this should be as simple as adding ToTable invocations for each entity that I want to remap in the DBContext's OnModelCreating method to override the default behaviour of TableName = EntityName. The problem is that this does indeed create a table mytesttable but the SQL created by Entity Framework at runtime still uses ApiResources in the query and consequently fails.

我采取的步骤是,我创建了一个从IdentityServer的 ConfigurationDbContext 派生的 DBContext ,以便能够覆盖 OnModelCreating 并自定义表名称:

The steps I've taken are I've created a DBContext that derives from IdentityServer's ConfigurationDbContext in order to be able to override OnModelCreating and customize the table names:

public class MyTestDbContext : ConfigurationDbContext { public MyTestDbContext(DbContextOptions<ConfigurationDbContext> options, ConfigurationStoreOptions storeOptions) : base(options, storeOptions) { } protected override void OnModelCreating(ModelBuilder modelBuilder) { Console.WriteLine("OnModelCreating invoking..."); base.OnModelCreating(modelBuilder); modelBuilder.Entity<IdentityServer4.EntityFramework.Entities.ApiResource>().ToTable("mytesttable"); base.OnModelCreating(modelBuilder); Console.WriteLine("...OnModelCreating invoked"); } }

我还实现了 DesignTimeDbContextFactoryBase< MyTestDBContext> 类,以在设计时通过 dotnet ef迁移调用时制造 MyTestDbContext 实例.命令行语法.

I've also implemented a DesignTimeDbContextFactoryBase<MyTestDBContext> class to manufacture the MyTestDbContext instance when invoked at design time via the dotnet ef migrations command line syntax.

这可行,对 dotnet ef迁移的调用会添加InitialIdentityServerConfigurationDbMigration -c MyTestDbContext -o Data/Migrations/IdentityServer/MyTestContext 在我的程序集中创建初始迁移.

This works and an invocation of dotnet ef migrations add InitialIdentityServerConfigurationDbMigration -c MyTestDbContext -o Data/Migrations/IdentityServer/MyTestContext creates the initial migrations in my assembly.

然后我启动IdentityServer实例,从 Startup 调用包含以下逻辑的测试方法:

I then start the IdentityServer instance, invoking a test method from Startup that contains the following logic:

private static void InitalizeDatabase(IApplicationBuilder app) { using (var serviceScope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope()) { serviceScope.ServiceProvider.GetRequiredService<PersistedGrantDbContext>().Database.Migrate(); var context = serviceScope.ServiceProvider.GetRequiredService<MyTestDbContext>(); context.Database.Migrate(); /* Add some test data here... */ } }

并且很高兴地使用 NpgSQL 提供程序在我的PostGRES数据库中徘徊并创建必要的表,包括名为 mytesttable 的表代替了 ApiResources 实体 IdentityServer4.EntityFramework.Entities.ApiResource .但是,当我从IdentityServer实例调用命令时,生成的SQL仍然引用 ApiResources 而不是 mytesttable :

and this happily wanders through and creates the necessary tables in my PostGRES database using NpgSQL provider, including the table named mytesttable in place of ApiResources for the entity IdentityServer4.EntityFramework.Entities.ApiResource. However, when I invoke a command from the IdentityServer instance, the SQL that is generated is still referencing ApiResources instead of mytesttable:

Failed executing DbCommand (2ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] SELECT x."Id", x."Description", x."DisplayName", x."Enabled", x."Name" FROM "ApiResources" AS x ORDER BY x."Id" Npgsql.PostgresException (0x80004005): 42P01: relation "ApiResources" does not exist

任何帮助表示赞赏.

推荐答案

此答案分为两部分;首先,需要在IdentityServer的配置中调整表名,以便它使用新的表名生成查询.第二;需要修改由实体框架生成的架构,以便它知道为Identity Framework实体创建名称不同的表.继续阅读...

There is two parts to this answer; firstly the table names need to be adjusted in IdentityServer's configuration so that it generates queries using the new table names. Secondly; the schema generated by entity framework needs to be amended so that it knows to create the differently named tables for the Identity Framework entities. Read on...

因此,首先;在 AddOperationalStore 和 AddConfigurationStore 方法上公开了更改Entity Framework查询中使用的表名的能力,这些方法与 AddIdentityServer 中间件方法无关.提供给配置方法的委托的 options 参数公开表名,例如: options.{EntityName} .Name = {WhateverTableNameYouWantToUse} -或 options.ApiResource.Name = mytesttable .您还可以通过调整 Schema 属性来在每个表的基础上覆盖该模式.

So, first up; the ability to change the table names used in the Entity Framework queries is exposed on AddOperationalStore and AddConfigurationStore methods that hang off the AddIdentityServer middleware method. The options argument of the delegate supplied to the configuration methods exposes the table names, for example: options.{EntityName}.Name = {WhateverTableNameYouWantToUse} - or options.ApiResource.Name = mytesttable. You can also override the schema on a per table basis as well by adjusting the Schema property.

下面的示例使用反射来更新所有实体,以使用以 idn _ 为前缀的表名,因此, idn_ApiResources , idn_ApiScopes 等:

The example below uses reflection to update all the entites to use table names prefixed with idn_, so idn_ApiResources, idn_ApiScopes etc:

services.AddIdentityServer() .AddConfigurationStore(options => { // Loop through and rename each table to 'idn_{tablename}' - E.g. `idn_ApiResources` foreach(var p in options.GetType().GetProperties()) { if (p.PropertyType == typeof(IdentityServer4.EntityFramework.Options.TableConfiguration)) { object o = p.GetGetMethod().Invoke(options, null); PropertyInfo q = o.GetType().GetProperty("Name"); string tableName = q.GetMethod.Invoke(o, null) as string; o.GetType().GetProperty("Name").SetMethod.Invoke(o, new object[] { $"idn_{tableName}" }); } } // Configure DB Context connection string and migrations assembly where migrations are stored options.ConfigureDbContext = builder => builder.UseNpgsql(_configuration.GetConnectionString("IDPDataDBConnectionString"), sql => sql.MigrationsAssembly(typeof(IdentityServer.Data.DbContexts.MyTestDbContext).GetTypeInfo().Assembly.GetName().Name)); } .AddOperationalStore(options => { // Copy and paste from AddConfigurationStore logic above. }

第二部分是修改实体框架从IdentityServer实体生成的架构.为此,您有两种选择:您可以从IdentityServer提供的DBContext之一中派生; ConfigurationDbContext 或 PeristedGrantDbContext ,然后覆盖 OnModelCreating 方法以将每个IdentityServer实体重新映射到修改后的表名,然后创建初始迁移或更新后的迁移为在此处记录(Fluent Api语法),或,您可以按照教程ConfigurationDbContext 和 PersistedGrantDbContext 创建初始迁移..io/zh-CN/release/quickstarts/8_entity_framework.html"rel =" nofollow noreferrer>添加迁移部分,然后对所有表名和对该表的引用进行查找并替换为文本编辑器创建的迁移文件中的名称.

The second part is to amend the schema generated by entity framework from the IdentityServer entities. To accomplish this you've got two choices; you can either derive from one of IdentityServer's supplied DBContexts; ConfigurationDbContext or PeristedGrantDbContext and then override the OnModelCreating method to remap each IdentityServer entity to the modified table name and then create your initial migration or updated migration as documented here (Fluent Api syntax), or you can create the initial migration from the supplied IdentityServer DBContext's ConfigurationDbContext and PersistedGrantDbContext as per the tutorial Adding Migrations section, and then just do a find and replace with a text editor on all the table names and references to those table names in the created migration files.

无论选择哪种方法,仍然需要使用 dotnet ef迁移... 命令行语法来创建初始迁移文件,如添加迁移或带有表更改的修改集,完成此操作后,运行IdentityServer项目和架构将在目标数据库中创建.

Whichever method you choose you will still need to use the dotnet ef migrations ... command line syntax to create either the initial migration files as shown in Adding Migrations or a modified set with table changes and once you've done this, run your IdentityServer project and the schema will be created in the target database.

注意; OnModelCreating 是通过 dotnet ef迁移语法(在设计时又名)以及在运行时调用的,如果您在自己的计算机上调用 Database.Migrate()DBContext-例如 MyDbContextInstance.Database.Migrate()(或异步等效方法).

Note; OnModelCreating is invoked via the dotnet ef migrations syntax (aka at Design Time) and also at runtime if you call Database.Migrate() on your DBContext - E.g. MyDbContextInstance.Database.Migrate() (or the async equivalent method).

如果要使用自定义的DBContext,以便自定义 OnModelCreating ,则需要添加一些设计时类,这些类在从调用 dotnet ef 时使用.命令行,然后将新的上下文添加到 Startup .

If you want to use a custom DBContext so you can customise OnModelCreating, you need to add a few design time classes which are used when you call dotnet ef from the command line and add the new context to Startup.

为完整起见,下面是一个粗糙的粗略示例,其中上下文目标是PostGres数据库(使用 UseSQLServer 代替 UseNpgsql 或您的后备存储是(不同)),并且appsettings.json文件中的连接字符串名称为 IDPDataDBConnectionString ,在这种情况下,自定义数据库上下文为 MyTestDbContext ,它源自IdentityServer的 ConfigurationDbContext .

For the sake of completeness below is a hacky rough example where the context target is a PostGres database (use UseSQLServer in place of UseNpgsql or whatever your backing store is if it differs) and the connection string name is IDPDataDBConnectionString in the appsettings.json file and the custom DB context in this case is MyTestDbContext which derives from IdentityServer's ConfigurationDbContext.

复制并粘贴代码,将路径调整为 appsettings.json (或重构),然后从命令行执行 dotnet ef迁移,添加InitialIdentityServerConfigurationDbMigration -c MyTestDbContext -o数据/迁移/IdentityServer/ConfigurationDbCreatedWithMyTestContext ,您应该看到Entity Framework使用您在派生上下文中放置在 OnModelCreating 中的任何替代项生成架构迁移文件.下面的示例还包括一些 Console.WriteLine 调用,以更轻松地跟踪正在发生的事情.

Copy and paste the code, adjust the path to appsettings.json (or refactor) and then from the command line execute dotnet ef migrations add InitialIdentityServerConfigurationDbMigration -c MyTestDbContext -o Data/Migrations/IdentityServer/ConfigurationDbCreatedWithMyTestContext and you should see the Entity Framework generate the schema migration files using whatever overrides you've placed in OnModelCreating on your derived context. The example below also includes some Console.WriteLine invocations to make it easier to track what's going on.

将此添加到启动:

services.AddDbContext<MyTestDbContext>(options => { options.UseNpgsql(_configuration.GetConnectionString("IDPDataDBConnectionString")); });

注意,如果需要,还可以使用设计时间类将IdentityServer数据库迁移文件分离到单独的类库中.如果执行此操作,请确保在启动中将其定位(请参见此处了解更多信息).

Note the use of the design time classes also allows you to separate your IdentityServer database migration files into a separate class library if you like. Make sure you target it in Startup if you do this (See here for more info).

namespace MyIdentityServer.DataClassLibrary.DbContexts { public class MyTestDbContext : ConfigurationDbContext { public MyTestDbContext(DbContextOptions<ConfigurationDbContext> options, ConfigurationStoreOptions storeOptions) : base(options, storeOptions) { } protected override void OnModelCreating(ModelBuilder modelBuilder) { Console.WriteLine("OnModelCreating invoking..."); base.OnModelCreating(modelBuilder); // Map the entities to different tables here modelBuilder.Entity<IdentityServer4.EntityFramework.Entities.ApiResource>().ToTable("mytesttable"); Console.WriteLine("...OnModelCreating invoked"); } } public class MyTestContextDesignTimeFactory : DesignTimeDbContextFactoryBase<MyTestDbContext> { public MyTestContextDesignTimeFactory() : base("IDPDataDBConnectionString", typeof(MyTestContextDesignTimeFactory).GetTypeInfo().Assembly.GetName().Name) { } protected override MyTestDbContext CreateNewInstance(DbContextOptions<MyTestDbContext> options) { var x = new DbContextOptions<ConfigurationDbContext>(); Console.WriteLine("Here we go..."); var optionsBuilder = newDbContextOptionsBuilder<ConfigurationDbContext>(); optionsBuilder.UseNpgsql("IDPDataDBConnectionString", postGresOptions => postGresOptions.MigrationsAssembly(typeof(MyTestContextDesignTimeFactory).GetTypeInfo().Assembly.GetName().Name)); DbContextOptions<ConfigurationDbContext> ops = optionsBuilder.Options; return new MyTestDbContext(ops, new ConfigurationStoreOptions()); } } /* Enable these if you just want to host your data migrations in a separate assembly and use the IdentityServer supplied DbContexts public class ConfigurationContextDesignTimeFactory : DesignTimeDbContextFactoryBase<ConfigurationDbContext> { public ConfigurationContextDesignTimeFactory() : base("IDPDataDBConnectionString", typeof(ConfigurationContextDesignTimeFactory).GetTypeInfo().Assembly.GetName().Name) { } protected override ConfigurationDbContext CreateNewInstance(DbContextOptions<ConfigurationDbContext> options) { return new ConfigurationDbContext(options, new ConfigurationStoreOptions()); } } public class PersistedGrantContextDesignTimeFactory : DesignTimeDbContextFactoryBase<PersistedGrantDbContext> { public PersistedGrantContextDesignTimeFactory() : base("IDPDataDBConnectionString", typeof(PersistedGrantContextDesignTimeFactory).GetTypeInfo().Assembly.GetName().Name) { } protected override PersistedGrantDbContext CreateNewInstance(DbContextOptions<PersistedGrantDbContext> options) { return new PersistedGrantDbContext(options, new OperationalStoreOptions()); } } */ public abstract class DesignTimeDbContextFactoryBase<TContext> : IDesignTimeDbContextFactory<TContext> where TContext : DbContext { protected string ConnectionStringName { get; } protected String MigrationsAssemblyName { get; } public DesignTimeDbContextFactoryBase(string connectionStringName, string migrationsAssemblyName) { ConnectionStringName = connectionStringName; MigrationsAssemblyName = migrationsAssemblyName; } public TContext CreateDbContext(string[] args) { return Create( Directory.GetCurrentDirectory(), Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"), ConnectionStringName, MigrationsAssemblyName); } protected abstract TContext CreateNewInstance( DbContextOptions<TContext> options); public TContext CreateWithConnectionStringName(string connectionStringName, string migrationsAssemblyName) { var environmentName = Environment.GetEnvironmentVariable( "ASPNETCORE_ENVIRONMENT"); var basePath = AppContext.BaseDirectory; return Create(basePath, environmentName, connectionStringName, migrationsAssemblyName); } private TContext Create(string basePath, string environmentName, string connectionStringName, string migrationsAssemblyName) { var builder = new ConfigurationBuilder() .SetBasePath(basePath) .AddJsonFile(@"c:\change\this\path\to\appsettings.json") .AddJsonFile($"appsettings.{environmentName}.json", true) .AddEnvironmentVariables(); var config = builder.Build(); var connstr = config.GetConnectionString(connectionStringName); if (String.IsNullOrWhiteSpace(connstr) == true) { throw new InvalidOperationException( "Could not find a connection string named 'default'."); } else { return CreateWithConnectionString(connstr, migrationsAssemblyName); } } private TContext CreateWithConnectionString(string connectionString, string migrationsAssemblyName) { if (string.IsNullOrEmpty(connectionString)) throw new ArgumentException( $"{nameof(connectionString)} is null or empty.", nameof(connectionString)); var optionsBuilder = new DbContextOptionsBuilder<TContext>(); Console.WriteLine( "MyDesignTimeDbContextFactory.Create(string): Connection string: {0}", connectionString); optionsBuilder.UseNpgsql(connectionString, postGresOptions => postGresOptions.MigrationsAssembly(migrationsAssemblyName)); DbContextOptions<TContext> options = optionsBuilder.Options; Console.WriteLine("Instancing...."); return CreateNewInstance(options); } } }

旁注;如果您已经有了一个包含IdentityServer表的数据库,则可以忽略EntityFrameworks迁移而手动对其重命名-然后,您唯一需要的就是将 Startup 中的内容更改为 AddConfigurationStore 和 AddOperationalStore .

Side note; If you've already got a database with the IdentityServer tables in, you can just rename them manually ignoring EntityFrameworks migrations - the only bit you'll then need is the changes in Startup to AddConfigurationStore and AddOperationalStore.

更多推荐

更改IdentityServer4实体框架表名称

本文发布于:2023-11-05 09:55:12,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1560531.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:实体   框架   名称

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!