Skip to content

'xml' Column Type on 'Log' entity incompatible with EntityFramework MySql #102

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
BenWolstencroft opened this issue Oct 26, 2018 · 4 comments
Assignees
Labels
question Further information is requested

Comments

@BenWolstencroft
Copy link

BenWolstencroft commented Oct 26, 2018

Hi

First off - great project...

.. but there's a but... We'd prefer to use MySql for the backend database, however the use of the 'xml' column type in the model annotations forces the use of an underlying database engine that supports that specific column type.

For now i've got around this by overriding the AdminDbContext with my own which replaces the xml column type with one compatible with MySql in the ModelBuilder (OnModelCreating) (see below)

using IdentityServer4.EntityFramework.Entities;
using IdentityServer4.EntityFramework.Extensions;
using IdentityServer4.EntityFramework.Options;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Skoruba.IdentityServer4.Admin.EntityFramework.Identity.Constants;
using Skoruba.IdentityServer4.Admin.EntityFramework.Entities;
using Skoruba.IdentityServer4.Admin.EntityFramework.Identity.Entities.Identity;
using Skoruba.IdentityServer4.Admin.EntityFramework.Identity.Interfaces;
using Skoruba.IdentityServer4.Admin.EntityFramework.Interfaces;
using System.Threading.Tasks;
using TableConst = Skoruba.IdentityServer4.Admin.EntityFramework.Constants;

namespace Identity.Server.EntityFramework
{
    public class AdminDbContext : IdentityDbContext<UserIdentity, UserIdentityRole, int, UserIdentityUserClaim, UserIdentityUserRole, UserIdentityUserLogin, UserIdentityRoleClaim, UserIdentityUserToken>,
        IAdminConfigurationDbContext, IAdminLogDbContext, IAdminPersistedGrantDbContext, IAdminPersistedGrantIdentityDbContext
    {
        private readonly ConfigurationStoreOptions _storeOptions;
        private readonly OperationalStoreOptions _operationalOptions;

        public AdminDbContext(DbContextOptions<AdminDbContext> options,
            ConfigurationStoreOptions storeOptions,
                OperationalStoreOptions operationalOptions)
            : base(options)
        {
            _storeOptions = storeOptions;
            _operationalOptions = operationalOptions;
        }

        public DbSet<ApiResource> ApiResources { get; set; }

        public DbSet<IdentityResource> IdentityResources { get; set; }

        public DbSet<ApiSecret> ApiSecrets { get; set; }

        public DbSet<ApiScope> ApiScopes { get; set; }

        public DbSet<ApiScopeClaim> ApiScopeClaims { get; set; }

        public DbSet<IdentityClaim> IdentityClaims { get; set; }

        public DbSet<ApiResourceClaim> ApiResourceClaims { get; set; }

        public DbSet<Client> Clients { get; set; }

        public DbSet<ClientGrantType> ClientGrantTypes { get; set; }

        public DbSet<ClientScope> ClientScopes { get; set; }

        public DbSet<ClientSecret> ClientSecrets { get; set; }

        public DbSet<ClientPostLogoutRedirectUri> ClientPostLogoutRedirectUris { get; set; }

        public DbSet<ClientCorsOrigin> ClientCorsOrigins { get; set; }

        public DbSet<ClientIdPRestriction> ClientIdPRestrictions { get; set; }

        public DbSet<ClientRedirectUri> ClientRedirectUris { get; set; }

        public DbSet<ClientClaim> ClientClaims { get; set; }

        public DbSet<ClientProperty> ClientProperties { get; set; }

        public DbSet<PersistedGrant> PersistedGrants { get; set; }

        public DbSet<Log> Logs { get; set; }

        public Task<int> SaveChangesAsync()
        {
            return base.SaveChangesAsync();
        }

        protected override void OnModelCreating(ModelBuilder builder)
        {
            base.OnModelCreating(builder);

            ConfigureIdentityContext(builder);
            ConfigureLogContext(builder);
            builder.ConfigureClientContext(_storeOptions);
            builder.ConfigureResourcesContext(_storeOptions);
            builder.ConfigurePersistedGrantContext(_operationalOptions);
        }

        private void ConfigureLogContext(ModelBuilder builder)
        {
            builder.Entity<Log>(log =>
            {
                log.ToTable(TableConst.TableConsts.Logging);
                log.HasKey(x => x.Id);
                log.Property(x => x.Properties).HasColumnType("longtext");
                log.Property(x => x.Level).HasMaxLength(128);
            });
        }

        private void ConfigureIdentityContext(ModelBuilder builder)
        {
            builder.Entity<UserIdentityRole>().ToTable(TableConsts.IdentityRoles);
            builder.Entity<UserIdentityRoleClaim>().ToTable(TableConsts.IdentityRoleClaims);
            builder.Entity<UserIdentityUserRole>().ToTable(TableConsts.IdentityUserRoles);

            builder.Entity<UserIdentity>().ToTable(TableConsts.IdentityUsers);
            builder.Entity<UserIdentityUserLogin>().ToTable(TableConsts.IdentityUserLogins);
            builder.Entity<UserIdentityUserClaim>().ToTable(TableConsts.IdentityUserClaims);
            builder.Entity<UserIdentityUserToken>().ToTable(TableConsts.IdentityUserTokens);
        }
    }
}

Just an fyi really.

Cheers!

@skoruba
Copy link
Owner

skoruba commented Oct 26, 2018

Hi @BenWolstencroft

You are right, unfortunatly - MySQL doesn't know anything about xml column, but you are solved very elegant. :)

Please take a look at - https://github.com/skoruba/IdentityServer4.Admin/blob/master/src/Skoruba.IdentityServer4.Admin/Helpers/StartupHelpers.cs#L139

I will consider to rewrite this part according database.

Thanks!

@skoruba skoruba self-assigned this Oct 26, 2018
@skoruba skoruba added the question Further information is requested label Oct 26, 2018
@svendu
Copy link
Contributor

svendu commented Jan 21, 2019

@skoruba #147 should take care of making it compatible with mysql. The replacement of the sink with the MySQL sink is only necessary, if you don't want to log to a file.

@skoruba
Copy link
Owner

skoruba commented Jan 30, 2019

Done, with PR from @svendu.
It will be merge into master.
Thank you.

@skoruba skoruba mentioned this issue Apr 4, 2019
@skoruba
Copy link
Owner

skoruba commented Apr 4, 2019

Done on master. Please check new release.
Thanks!

@skoruba skoruba closed this as completed Apr 4, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

3 participants