Skip to content
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

Set value comparer for ExtraProperties and Properties dictionary. #2462

Merged
merged 11 commits into from
Jan 8, 2020
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Newtonsoft.Json;
using Volo.Abp.Auditing;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Entities.Events;
using Volo.Abp.EntityFrameworkCore.EntityHistory;
using Volo.Abp.EntityFrameworkCore.Modeling;
using Volo.Abp.EntityFrameworkCore.ValueConverters;
using Volo.Abp.Guids;
using Volo.Abp.MultiTenancy;
Expand Down Expand Up @@ -352,147 +352,9 @@ protected virtual void ConfigureBaseProperties<TEntity>(ModelBuilder modelBuilde
return;
}

ConfigureConcurrencyStampProperty<TEntity>(modelBuilder, mutableEntityType);
ConfigureExtraProperties<TEntity>(modelBuilder, mutableEntityType);
ConfigureAuditProperties<TEntity>(modelBuilder, mutableEntityType);
ConfigureTenantIdProperty<TEntity>(modelBuilder, mutableEntityType);
ConfigureGlobalFilters<TEntity>(modelBuilder, mutableEntityType);
}

protected virtual void ConfigureConcurrencyStampProperty<TEntity>(ModelBuilder modelBuilder, IMutableEntityType mutableEntityType)
where TEntity : class
{
if (!typeof(IHasConcurrencyStamp).IsAssignableFrom(typeof(TEntity)))
{
return;
}

modelBuilder.Entity<TEntity>(b =>
{
b.Property(x => ((IHasConcurrencyStamp) x).ConcurrencyStamp)
.IsConcurrencyToken()
.HasColumnName(nameof(IHasConcurrencyStamp.ConcurrencyStamp));
});
}

protected virtual void ConfigureExtraProperties<TEntity>(ModelBuilder modelBuilder, IMutableEntityType mutableEntityType)
where TEntity : class
{
if (!typeof(IHasExtraProperties).IsAssignableFrom(typeof(TEntity)))
{
return;
}

modelBuilder.Entity<TEntity>(b =>
{
b.Property(x => ((IHasExtraProperties) x).ExtraProperties)
.HasConversion(
d => JsonConvert.SerializeObject(d, Formatting.None),
s => JsonConvert.DeserializeObject<Dictionary<string, object>>(s)
)
.HasColumnName(nameof(IHasExtraProperties.ExtraProperties));
});
}

protected virtual void ConfigureAuditProperties<TEntity>(ModelBuilder modelBuilder, IMutableEntityType mutableEntityType)
where TEntity : class
{
if (typeof(TEntity).IsAssignableTo<IHasCreationTime>())
{
modelBuilder.Entity<TEntity>(b =>
{
b.Property(x => ((IHasCreationTime)x).CreationTime)
.IsRequired()
.HasColumnName(nameof(IHasCreationTime.CreationTime));
});
}
modelBuilder.Entity<TEntity>().ConfigureByConvention();

if (typeof(TEntity).IsAssignableTo<IMayHaveCreator>())
{
modelBuilder.Entity<TEntity>(b =>
{
b.Property(x => ((IMayHaveCreator)x).CreatorId)
.IsRequired(false)
.HasColumnName(nameof(IMayHaveCreator.CreatorId));
});
}

if (typeof(TEntity).IsAssignableTo<IMustHaveCreator>())
{
modelBuilder.Entity<TEntity>(b =>
{
b.Property(x => ((IMustHaveCreator)x).CreatorId)
.IsRequired()
.HasColumnName(nameof(IMustHaveCreator.CreatorId));
});
}

if (typeof(TEntity).IsAssignableTo<IHasModificationTime>())
{
modelBuilder.Entity<TEntity>(b =>
{
b.Property(x => ((IHasModificationTime)x).LastModificationTime)
.IsRequired(false)
.HasColumnName(nameof(IHasModificationTime.LastModificationTime));
});
}

if (typeof(TEntity).IsAssignableTo<IModificationAuditedObject>())
{
modelBuilder.Entity<TEntity>(b =>
{
b.Property(x => ((IModificationAuditedObject)x).LastModifierId)
.IsRequired(false)
.HasColumnName(nameof(IModificationAuditedObject.LastModifierId));
});
}

if (typeof(TEntity).IsAssignableTo<ISoftDelete>())
{
modelBuilder.Entity<TEntity>(b =>
{
b.Property(x => ((ISoftDelete) x).IsDeleted)
.IsRequired()
.HasDefaultValue(false)
.HasColumnName(nameof(ISoftDelete.IsDeleted));
});
}

if (typeof(TEntity).IsAssignableTo<IHasDeletionTime>())
{
modelBuilder.Entity<TEntity>(b =>
{
b.Property(x => ((IHasDeletionTime)x).DeletionTime)
.IsRequired(false)
.HasColumnName(nameof(IHasDeletionTime.DeletionTime));
});
}

if (typeof(TEntity).IsAssignableTo<IDeletionAuditedObject>())
{
modelBuilder.Entity<TEntity>(b =>
{
b.Property(x => ((IDeletionAuditedObject)x).DeleterId)
.IsRequired(false)
.HasColumnName(nameof(IDeletionAuditedObject.DeleterId));
});
}
}

protected virtual void ConfigureTenantIdProperty<TEntity>(ModelBuilder modelBuilder, IMutableEntityType mutableEntityType)
where TEntity : class
{
if (!typeof(TEntity).IsAssignableTo<IMultiTenant>())
{
return;
}

modelBuilder.Entity<TEntity>(b =>
{
b.Property(x => ((IMultiTenant)x).TenantId)
.IsRequired(false)
.HasColumnName(nameof(IMultiTenant.TenantId));
});
ConfigureGlobalFilters<TEntity>(modelBuilder, mutableEntityType);
}

protected virtual void ConfigureGlobalFilters<TEntity>(ModelBuilder modelBuilder, IMutableEntityType mutableEntityType)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Newtonsoft.Json;
using Volo.Abp.Auditing;
using Volo.Abp.Data;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Entities.Auditing;
using Volo.Abp.EntityFrameworkCore.ValueComparers;
using Volo.Abp.EntityFrameworkCore.ValueConverters;
using Volo.Abp.MultiTenancy;

namespace Volo.Abp.EntityFrameworkCore.Modeling
Expand Down Expand Up @@ -57,11 +57,9 @@ public static void TryConfigureExtraProperties(this EntityTypeBuilder b)
if (b.Metadata.ClrType.IsAssignableTo<IHasExtraProperties>())
{
b.Property<Dictionary<string, object>>(nameof(IHasExtraProperties.ExtraProperties))
.HasConversion(
d => JsonConvert.SerializeObject(d, Formatting.None),
s => JsonConvert.DeserializeObject<Dictionary<string, object>>(s)
)
.HasColumnName(nameof(IHasExtraProperties.ExtraProperties));
.HasColumnName(nameof(IHasExtraProperties.ExtraProperties))
.HasConversion(new AbpJsonValueConverter<Dictionary<string, object>>())
.Metadata.SetValueComparer(new AbpDictionaryValueComparer());
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore.ChangeTracking;

namespace Volo.Abp.EntityFrameworkCore.ValueComparers
{
public class AbpDictionaryValueComparer : ValueComparer<Dictionary<string, object>>
{
public AbpDictionaryValueComparer()
: base(
(d1, d2) => d1.SequenceEqual(d2),
d => d.Aggregate(0, (k, v) => HashCode.Combine(k, v.GetHashCode())),
d => d.ToDictionary(k => k.Key, v => v.Value))
{
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Newtonsoft.Json;

namespace Volo.Abp.EntityFrameworkCore.ValueConverters
{
public class AbpJsonValueConverter<TPropertyType> : ValueConverter<TPropertyType, string>
{
public AbpJsonValueConverter()
: base(
d => JsonConvert.SerializeObject(d, Formatting.None),
s => JsonConvert.DeserializeObject<TPropertyType>(s))
{
}
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore.Modeling;
using Volo.Abp.EntityFrameworkCore.ValueComparers;
using Volo.Abp.EntityFrameworkCore.ValueConverters;
using Volo.Abp.IdentityServer.ApiResources;
using Volo.Abp.IdentityServer.Clients;
using Volo.Abp.IdentityServer.Grants;
Expand Down Expand Up @@ -202,10 +203,8 @@ public static void ConfigureIdentityServer(
identityResource.Property(x => x.DisplayName).HasMaxLength(IdentityResourceConsts.DisplayNameMaxLength);
identityResource.Property(x => x.Description).HasMaxLength(IdentityResourceConsts.DescriptionMaxLength);
identityResource.Property(x => x.Properties)
.HasConversion(
d => JsonConvert.SerializeObject(d, Formatting.None),
s => JsonConvert.DeserializeObject<Dictionary<string, string>>(s)
);
.HasConversion(new AbpJsonValueConverter<Dictionary<string, object>>())
.Metadata.SetValueComparer(new AbpDictionaryValueComparer());

identityResource.HasMany(x => x.UserClaims).WithOne().HasForeignKey(x => x.IdentityResourceId).IsRequired();
});
Expand All @@ -229,10 +228,8 @@ public static void ConfigureIdentityServer(
apiResource.Property(x => x.DisplayName).HasMaxLength(ApiResourceConsts.DisplayNameMaxLength);
apiResource.Property(x => x.Description).HasMaxLength(ApiResourceConsts.DescriptionMaxLength);
apiResource.Property(x => x.Properties)
.HasConversion(
d => JsonConvert.SerializeObject(d, Formatting.None),
s => JsonConvert.DeserializeObject<Dictionary<string, string>>(s)
);
.HasConversion(new AbpJsonValueConverter<Dictionary<string, object>>())
.Metadata.SetValueComparer(new AbpDictionaryValueComparer());

apiResource.HasMany(x => x.Secrets).WithOne().HasForeignKey(x => x.ApiResourceId).IsRequired();
apiResource.HasMany(x => x.Scopes).WithOne().HasForeignKey(x => x.ApiResourceId).IsRequired();
Expand Down