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

时间:2018-10-03 01:06:38

标签: c# asp.net-core-2.1 entity-framework-core-2.1

我从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,因为我不想使用dto继承Table Per Hierarchy。

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

  

“无法将索引{'CreatedAt'}添加到实体类型   “订阅”,因为已经存在相同属性的索引   在实体类型“ Dto”上

现在我已经搜索了该错误,但是在任何地方都找不到解决方法。

是否应该删除dto类,并向表示模型的每个对象添加相同的属性?

2 个答案:

答案 0 :(得分:2)

由于错误状态,并且索引已经在基类的属性上定义。检查属性是否以您当前正在处理的实体的相同类型声明,类似于:

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

答案 1 :(得分:1)

我最终删除了以下几行:

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

由于某种原因,它们在实体框架层次结构中包括了Dto类,从而为每个层次结构继承创建了一个表(仅产生一个表数据库)。

然后我像这样重写了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创建的表,则更改仅针对从Dto继承的对象进行。

此代码:

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

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

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

,最后,此代码出现错误,因为Dto类已包含在数据库实体中,因此它为其创建了索引,并且由于在数据库实体中包含该类时,当下一个实体尝试执行TPH时会触发TPH。同样创建一个索引,则会弹出错误(我们尝试在同一表中创建同一索引,因为使用TPH时,我们只有一个表)。

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;
            }
        }

但是现在我们已经为每个实体分离了表格,

Moho's answer很有帮助。

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

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

EF Core Add Migration Debugging