Я работаю над еще одной версией Onion Architecture, использующей EF в базовой среде. У меня есть какое-то сопоставление, которое я хочу, чтобы оно применялось почти ко всем таблицам, которые у меня есть, и, поскольку сопоставление каким-то образом логично в моем сценарии, я хочу устранить пробел в уме и у коллег, уменьшив дальнейшее повреждение данных.
Так что я не прошел шаг за шагом «Отражение», пытаясь достичь следующего сценария:
for (all registered model in context) {
if(model has IXyz interface) {
* builder apply mapping on entity
}
}
Знак зодиака (): * Отображение, которое я хочу настроить в точке * следующим образом:
builder.Entity<Sample>().HasQueryFilter(m => EF.Property<bool>(m, nameof(IDeletableEntity.IsDeleted)) == false);
Я пробовал много вещей, но ни одна не работала; Я перепрыгивал с ошибки на ошибку, как во время выполнения, так и во время компиляции:
1.
System.ArgumentException: для метода Stati c требуется нулевой экземпляр, не статический * Метод 1041 * требует ненулевого экземпляра. '
2.
System.ArgumentException:' Method 'Boolean b__6_0 (Microsoft.EntityFrameworkCore.Metadata.Builders.EntityTypeBuilder 1[Template.Domain.Models.Sample])'
declared on type
'Template.Data.Configurations.ApplicationDbContext+<>c__6
1 [Microsoft.EntityFrameworkCore.Metadata.Builders.EntityTypeBuilder`1 [Template.Domain.Models.Sample]] 'нельзя вызвать с экземпляром типа' Template.Data.Configurations.ApplicationDbContext ''
3.
Ошибка CS1660 Невозможно преобразовать лямбда-выражение в тип 'Выражение', поскольку оно не является делегатом
Последнее состояние моего кода:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Template.Domain.Interfaces;
using Template.Domain.Models;
namespace Template.Data.Configurations
{
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public virtual DbSet<Sample> Samples { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
Debugger.Launch();
var modelBuilderMethods = builder.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance);
MethodInfo desiredModelBuilderMethod = modelBuilderMethods.FirstOrDefault(modelBuilderMethod => modelBuilderMethod.Name == nameof(builder.Entity) && modelBuilderMethod.IsGenericMethod && modelBuilderMethod.IsGenericMethodDefinition && modelBuilderMethod.GetParameters().Length == 0); //Entity<T>() Method
//builder.Entity<Sample>().HasQueryFilter(m => EF.Property<bool>(m, nameof(IDeletableEntity.IsDeleted)) == false);
foreach (var entityType in builder.Model.GetEntityTypes())
{
if (entityType.ClrType.GetInterfaces().Any(w => w == typeof(IDeletableEntity)))
{
var entityGenericMethod = desiredModelBuilderMethod.MakeGenericMethod(entityType.ClrType);
var entity = entityGenericMethod.Invoke(builder, new object[0]);
var entityTypeBuilder = entity.GetType();
var entityTypeBuilderMethods = entityTypeBuilder.GetMethods(BindingFlags.Public | BindingFlags.Instance);
MethodInfo desiredEntityTypeBuilder = entityTypeBuilderMethods.FirstOrDefault(entityTypeBuilderMethod => entityTypeBuilderMethod.Name == nameof(EntityTypeBuilder.HasQueryFilter) && !entityTypeBuilderMethod.IsGenericMethod && !entityTypeBuilderMethod.IsGenericMethodDefinition); //HasQueryFilter(Expression<Func<T, bool>> filter) Method
var queryFilterMethod = this.GetType()
.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic)
.FirstOrDefault(w => w.Name == nameof(SetQueryFilters)
&& w.IsGenericMethod
&& w.IsGenericMethodDefinition
&& w.GetParameters().Length == 0)
?.MakeGenericMethod(entity.GetType());
var lambdaExpression = queryFilterMethod.Invoke(this, new object[0]);
desiredEntityTypeBuilder.Invoke(entity, new object[]
{
lambdaExpression
});
}
}
}
private Expression<Func<T, bool>> SetQueryFilters<T>()
{
var func = new Func<T, bool>(m=> EF.Property<bool>(m, nameof(IDeletableEntity.IsDeleted)) == false);
var exp = Expression.Default(typeof(ApplicationDbContext)); //Expression.Constant(this);
var methodCallExpression = Expression.Call(exp, func.Method);
var expression = Expression.Lambda<Func<T, bool>>(methodCallExpression);
return expression;
}
}
}
namespace Template.Domain.Interfaces
{
public interface IDeletableEntity
{
bool IsDeleted { get; set; }
}
}
using System.ComponentModel.DataAnnotations.Schema;
using Template.Domain.Interfaces;
namespace Template.Domain.Models
{
public class Sample : IDeletableEntity
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public bool IsDeleted { get; set; }
}
}
Примечание для Отладка Этот код необходимо вызвать «Update-Database» в «Консоли диспетчера пакетов».
Спасибо, Хассан.