Api/Netina.Repository/Extensions/ModelBuilderExtensions.cs

190 lines
7.9 KiB
C#

namespace Netina.Repository.Extensions;
public class ModelBuilderQueryFilter
{
public void AddQueryFilterToModelBuilder(ModelBuilder modelBuilder, Type type)
{
var method = GetType().GetMethod("RegisterQueryFilter").MakeGenericMethod(type);
method.Invoke(this, new object[] { modelBuilder });
}
public void RegisterQueryFilter<TQFilter>(ModelBuilder modelBuilder) where TQFilter : ApiEntity
{
var tt = typeof(TQFilter);
if (tt.BaseType == typeof(ApiEntity))
modelBuilder.Entity<TQFilter>().HasQueryFilter(e => e.IsRemoved == false);
}
}
public static class ModelBuilderExtensions
{
/// <summary>
/// Singularizin table name like Posts to Post or People to Person
/// </summary>
/// <param name="modelBuilder"></param>
public static void AddSingularizingTableNameConvention(this ModelBuilder modelBuilder)
{
var pluralizer = new Pluralizer();
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
{
var tableName = entityType.GetTableName();
entityType.SetTableName(pluralizer.Singularize(tableName));
}
}
/// <summary>
/// Set NEWSEQUENTIALID() sql function for all columns named "Id"
/// </summary>
/// <param name="modelBuilder"></param>
/// <param name="mustBeIdentity">Set to true if you want only "Identity" guid fields that named "Id"</param>
public static void AddSequentialGuidForIdConvention(this ModelBuilder modelBuilder)
{
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
{
var property = entityType.GetProperties()
.Where(p => p.Name.Contains("Id", StringComparison.OrdinalIgnoreCase))
.ToArray();
foreach (var mutableProperty in property)
modelBuilder.AddDefaultValueSqlConvention(mutableProperty?.Name, typeof(Guid), "gen_random_uuid()");
}
}
/// <summary>
/// Set DefaultValueSql for sepecific property name and type
/// </summary>
/// <param name="modelBuilder"></param>
/// <param name="propertyName">Name of property wants to set DefaultValueSql for</param>
/// <param name="propertyType">Type of property wants to set DefaultValueSql for </param>
/// <param name="defaultValueSql">DefaultValueSql like "NEWSEQUENTIALID()"</param>
public static void AddDefaultValueSqlConvention(this ModelBuilder modelBuilder, string propertyName,
Type propertyType, string defaultValueSql)
{
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
{
var property = entityType.GetProperties()
.SingleOrDefault(p => p.Name.Equals(propertyName, StringComparison.OrdinalIgnoreCase));
if (property != null && property.ClrType == propertyType)
property.SetDefaultValueSql(defaultValueSql);
}
}
/// <summary>
/// Set DeleteBehavior.Restrict by default for relations
/// </summary>
/// <param name="modelBuilder"></param>
public static void AddRestrictDeleteBehaviorConvention(this ModelBuilder modelBuilder)
{
var cascadeFKs = modelBuilder.Model.GetEntityTypes()
.SelectMany(t => t.GetForeignKeys())
.Where(fk => !fk.IsOwnership && fk.DeleteBehavior == DeleteBehavior.Cascade);
foreach (var fk in cascadeFKs)
{
fk.DeleteBehavior = DeleteBehavior.Restrict;
fk.IsRequired = false;
}
}
/// <summary>
/// Dynamicaly load all IEntityTypeConfiguration with Reflection
/// </summary>
/// <param name="modelBuilder"></param>
/// <param name="assemblies">Assemblies contains Entities</param>
public static void RegisterEntityTypeConfiguration(this ModelBuilder modelBuilder, params Assembly[] assemblies)
{
var applyGenericMethod = typeof(ModelBuilder)
.GetMethods()
.First(m => m.Name == nameof(ModelBuilder.ApplyConfiguration));
var types = assemblies.SelectMany(a => a.GetExportedTypes())
.Where(c => c.IsClass && !c.IsAbstract && c.IsPublic);
foreach (var type in types)
foreach (var iface in type.GetInterfaces())
if (iface.IsConstructedGenericType &&
iface.GetGenericTypeDefinition() == typeof(IEntityTypeConfiguration<>))
{
var applyConcreteMethod = applyGenericMethod.MakeGenericMethod(iface.GenericTypeArguments[0]);
applyConcreteMethod.Invoke(modelBuilder, new[] { Activator.CreateInstance(type) });
}
}
/// <summary>
/// Pluralizing table name like Post to Posts or Person to People
/// </summary>
/// <param name="modelBuilder"></param>
public static void AddPluralizingTableNameConvention(this ModelBuilder modelBuilder)
{
var pluralizer = new Pluralizer();
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
if (entityType.BaseType == null)
{
var tableName = entityType.GetTableName();
entityType.SetTableName(pluralizer.Pluralize(tableName));
}
}
/// <summary>
/// Dynamicaly register all Entities that inherit from specific BaseType
/// </summary>
/// <param name="modelBuilder"></param>
/// <param name="baseType">Base type that Entities inherit from this</param>
/// <param name="assemblies">Assemblies contains Entities</param>
public static void RegisterAllEntities<BaseType>(this ModelBuilder modelBuilder,
ILogger<ApplicationContext> _logger, params Assembly[] assemblies) where BaseType : ApiEntity
{
var types = assemblies.SelectMany(a => a.GetExportedTypes())
.Where(c => c.IsClass && !c.IsAbstract && c.IsPublic && typeof(BaseType)
.IsAssignableFrom(c));
var builderQueryFilter = new ModelBuilderQueryFilter();
foreach (var type in types)
{
modelBuilder.Entity(type);
builderQueryFilter.AddQueryFilterToModelBuilder(modelBuilder, type);
}
}
/// <summary>
/// Dynamicaly register all Entities that inherit from specific BaseType
/// </summary>
/// <param name="modelBuilder"></param>
/// <param name="baseType">Base type that Entities inherit from this</param>
/// <param name="assemblies">Assemblies contains Entities</param>
public static void RegisterAllEntitiesV02<BaseType>(this ModelBuilder builder, ILogger<ApplicationContext> _logger, params Assembly[] assemblies) where BaseType : ApiEntity
{
var types = assemblies.SelectMany(a => a.GetExportedTypes())
.Where(c => c.IsClass && !c.IsAbstract && c.IsPublic && typeof(BaseType)
.IsAssignableFrom(c));
var builderQueryFilter = new ModelBuilderQueryFilter();
foreach (var type in types)
{
var stopwatch = new Stopwatch();
stopwatch.Start();
// On Model Creating
var onModelCreatingMethod =
type.GetMethods().FirstOrDefault(x => x.Name == "OnModelCreating");
if (onModelCreatingMethod != null)
onModelCreatingMethod.Invoke(type, new object[] { builder });
else
{
// On Base Model Creating
if (type.BaseType == null || type.BaseType != typeof(BaseType)) continue;
var baseOnModelCreatingMethod = type.BaseType.GetMethods()
.FirstOrDefault(x => x.Name == "OnModelCreating");
if (baseOnModelCreatingMethod == null)
continue;
baseOnModelCreatingMethod.Invoke(typeof(BaseType), new object[] { builder });
}
builderQueryFilter.AddQueryFilterToModelBuilder(builder, type);
stopwatch.Stop();
_logger.LogInformation($"MODEL BUILDER {type.Name} In : {stopwatch.ElapsedMilliseconds}ms");
}
}
}