来自基础 class 的索引数据注释异常

Exception on index data annotations from a base class

我从 ASP.net Core 开始创建我的模型。
我刚刚创建了两个:一个叫做 dto,它将成为我所有数据库模型的基础,看起来像这样:

public abstract class Dto
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid Id { get; set; }
    [Clustered]
    public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
    public DateTime LastUpdate { set; get; } 
}

另一个叫做 subscription,它看起来像这样:

public class Subscription:Dto
{
    public string Name { get; set; } 
    public decimal Price { set; get; }
    public string MeliApiKey { get; set; }
    public int MaxQueries { get; set; }
    public int UsedQueries { get; set; }

}

我在 Fluent API 上有以下配置:

modelBuilder.Entity<Dto.Dto>().Property(x => x.CreatedAt).HasDefaultValueSql("SYSUTCDATETIME()");
modelBuilder.Entity<Dto.Dto>().Property(x => x.LastUpdate).HasComputedColumnSql("SYSUTCDATETIME()");

foreach (var entity in modelBuilder.Model.GetEntityTypes())
{
    foreach (var prop in entity.GetProperties())
    {
        var attr = prop.PropertyInfo?.GetCustomAttribute<ClusteredAttribute>(true);
        if (attr != null)
        {
            var index = entity.AddIndex(prop);
            index.IsUnique = true;
            index.SqlServer().IsClustered = true;
        }
    }
}

我只添加了 subscription 作为 dbset,因为我不想 Table Per Hierarchy 继承 dto

当我 运行 添加迁移时,出现以下错误:

"The index {'CreatedAt'} cannot be added to the entity type 'Subscription' because an index on the same properties already exists on entity type 'Dto'"

现在我用谷歌搜索了这个错误,但我没有看到任何解决方法。

我是否应该删除 dto class 并将相同的属性添加到将代表我的模型的每个对象?

如错误所述,索引已在 属性 上为基础 class 定义。检查 属性 是否在您当前正在处理的实体的同一类型中声明,类似于:

var propertiesToProcess = entity.GetProperties()
    .Where( p => entity.ClrType == p.PropertyInfo.DeclaringType );

我最终删除了这些行:

modelBuilder.Entity<Dto.Dto>().Property(x => x.CreatedAt).HasDefaultValueSql("SYSUTCDATETIME()");
modelBuilder.Entity<Dto.Dto>().Property(x => x.LastUpdate).HasComputedColumnSql("SYSUTCDATETIME()");

因为他们出于某种原因在 Entity Framework 层次结构中包含了 Dto class,为每个层次结构继承创建了一个 Table(结果只有一个 table 数据库)。

然后我像这样重写了 OnModelCreating 的代码:

foreach (var entity in modelBuilder.Model.GetEntityTypes())
        {
            if (entity.ClrType.IsSubclassOf(typeof(Dto.Dto)))
            {

                modelBuilder.Entity(entity.ClrType)
                    .HasKey(nameof(Dto.Dto.Id)).ForSqlServerIsClustered(false);

                modelBuilder.Entity(entity.ClrType)
                    .Property(nameof(Dto.Dto.CreatedAt))
                    .HasDefaultValueSql("SYSUTCDATETIME()");

                modelBuilder.Entity(entity.ClrType)
                    .Property(nameof(Dto.Dto.LastUpdate))
                    .HasComputedColumnSql("SYSUTCDATETIME()");

                foreach (var prop in entity.GetProperties())
                {

                    var attr = prop.PropertyInfo?.GetCustomAttribute<ClusteredAttribute>(true);
                    if (attr != null)
                    {
                        var index = entity.AddIndex(prop);
                        index.IsUnique = true;
                        index.SqlServer().IsClustered = true;

                    }

                }
            }
        }

如果 if (entity.ClrType.IsSubclassOf(typeof(Dto.Dto))) 是为了快速丢弃由 ASP.net Core 创建的 tables,因此仅对我从 Dto 继承的对象进行更改。

此代码:

modelBuilder.Entity(entity.ClrType)
                .Property(nameof(Dto.Dto.CreatedAt))
                .HasDefaultValueSql("SYSUTCDATETIME()");

modelBuilder.Entity(entity.ClrType)
                .Property(nameof(Dto.Dto.LastUpdate))
                .HasComputedColumnSql("SYSUTCDATETIME()");

告诉 entity framework 使用当前 UTC 时间创建具有默认值的列 CreateAt 并使用 for 循环中实际实体的当前 UTC 时间更新 LastUpdate 列。

最后,此代码出现错误,因为 Dto class 被包含在数据库实体中,因此它为其创建索引,并且由于在数据库实体中包含 class当下一个实体也试图创建索引时触发 TPH,错误弹出(我们试图在相同的 table 中创建相同的索引,因为使用 TPH 我们只有一个 table)。

foreach (var prop in entity.GetProperties())
        {

            var attr = prop.PropertyInfo?.GetCustomAttribute<ClusteredAttribute>(true);
            if (attr != null)
            {
                var index = entity.AddIndex(prop);
                index.IsUnique = true;
                index.SqlServer().IsClustered = true;
            }
        }

但现在我们已经为每个实体分离了 tables,它就可以正常工作了。

帮了大忙。

这里有其他帮助我实现这一目标的答案:

How do I check if a type is a subtype OR the type of an object?