190 lines
7.9 KiB
C#
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, [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, [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, [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), [builder]);
|
|
}
|
|
|
|
builderQueryFilter.AddQueryFilterToModelBuilder(builder, type);
|
|
stopwatch.Stop();
|
|
_logger.LogInformation($"MODEL BUILDER {type.Name} In : {stopwatch.ElapsedMilliseconds}ms");
|
|
}
|
|
}
|
|
} |