EFCore 3.1 添加默认影子属性并将它们用于软删除

EFCore 3.1 Adding default shadow properties and use them for softdelete

我正在使用 C# .NET Core 3.1 和 EFCore 开发应用程序。基于 this document,我尝试添加新列并使用 Queryfilter。

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

            modelBuilder.ApplyConfiguration(new UserEntityTypeConfiguration());
            ....
            //Other configurations
            ...

            // Assures consistent naming and configuration of audit fields.
            foreach (IMutableEntityType entityType in modelBuilder.Model.GetEntityTypes().Where(item => !item.IsOwned()))
            {
                //Settings related to softdelete
                modelBuilder.Entity(entityType.Name).Property<bool>(nameof(DefaultColumnName.IsDeleted)).HasDefaultValue(false);
                var IsDeletedProperty = entityType.FindProperty(nameof(DefaultColumnName.IsDeleted));
                if (IsDeletedProperty != null && IsDeletedProperty.ClrType == typeof(bool))
                {
                    var parameter = Expression.Parameter(entityType.ClrType, "p");
                    var prop = Expression.Property(parameter, IsDeletedProperty.PropertyInfo);
                    var filter = Expression.Lambda(Expression.Not(prop), parameter);
                    MutableEntityTypeExtensions.SetQueryFilter(entityType, filter);
                }
            }

但是,当我使用dotnet ef migrations add Init迁移时,出现以下错误并且无法顺利迁移。

Value cannot be null. (Parameter 'property')

根据我的调查,这个错误发生在这一行,但我不知道如何解决这个问题。

var prop = Expression.Property(parameter, IsDeletedProperty.PropertyInfo);

谁能告诉我如何解决这个问题?

阴影属性不是 class 的真实属性,因此没有关联的 PropertyInfoFieldInfo。如 访问影子属性中所述 :

  1. Shadow property values can be obtained and changed through the ChangeTracker API
  2. Shadow properties can be referenced in LINQ queries via the EF.Property static method

第二个也适用于过滤器表达式。所以你需要 属性 访问器,比如

EF.Property<bool>(p, "IsDeleted")

这对于您的代码意味着如下更改相关行

var prop = Expression.Call(
    typeof(EF), nameof(EF.Property), new[] { typeof(bool) },
    parameter, Expression.Constant(IsDeletedProperty.Name));