我从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
类,并向表示模型的每个对象添加相同的属性?
答案 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?