如何在使用 TPT 层次结构时首先在 EF 代码中实现并发
Posted
技术标签:
【中文标题】如何在使用 TPT 层次结构时首先在 EF 代码中实现并发【英文标题】:How to implement Concurrency in EF code first while using a TPT hierarchy 【发布时间】:2011-04-08 09:56:55 【问题描述】:大家好!我正在尝试首先使用实体框架代码实现乐观并发检查(通过 nuget 安装,所以我假设它是最后一个 RC)。但是,我似乎无法让它工作。我有以下类层次结构
public abstract class DbEntityBase
/// <summary>
/// Autogenerated primary key for the object
/// </summary>
public Guid Id get; private set;
protected DbEntityBase()
Id = Guid.NewGuid();
//Some override for equality, omitted for brievity
public class Drawing : DbEntityBase
public string Name get; set;
//Just an implementation of ICollection<DrawingVersion>
public DrawingVersionCollection Versions get; private set;
public Drawing()
Name = "New Drawing";
Versions = new DrawingVersionCollection(this);
public class DrawingVersion : DbEntityBase
public string Name get; set;
public DateTime Started get; set;
public DateTime LastModified get; set;
public DrawingFile File get; private set;
public Drawing Owner get; internal set;
internal DrawingVersion()
Name = "New Version";
Started = DateTime.Now;
LastModified = DateTime.Now;
File = new DrawingFile();
我正在使用以下 DbContext 来持久化它们
public class PortfolioContext : DbContext
public DbSet<Drawing> Drawings get; set;
protected override void OnModelCreating(DbModelBuilder modelBuilder)
//Key mapping
modelBuilder.Entity<DbEntityBase>()
.HasKey(e => e.Id);
//Table Mapping
modelBuilder.Entity<DrawingVersion>().ToTable("DrawingVersion");
modelBuilder.Entity<Drawing>().ToTable("Drawing");
//Ignored fields
modelBuilder.Entity<DrawingVersion>()
.Ignore(v => v.Owner);
所有这些工作都很好,花花公子。如果我检查生成的模式,我会看到表格,一个用于绘图,一个用于 DrawingVersion。我可以毫无问题地阅读、更新和删除。
当我想为我的实体添加时间戳时出现了问题。起初我做了一件很幼稚的事情。我在 DbEntityBase 中添加了以下内容
public byte[] Timestamp get; set;
在我的上下文中那些行
//Versionning mapping
modelBuilder.Entity<DbEntityBase>()
.Property(e => e.Timestamp)
.IsConcurrencyToken()
.HasColumnType("timestamp")
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed);
但是,在模式生成期间,它失败并出现以下异常
System.NotSupportedException : 存储生成的模式“计算”是 不支持的属性 不是“时间戳”类型或 '行版本'。
那时我有点讽刺。 “哎呀,我就是这样,把 timestamp 放在列类型中,而我应该把 timestamp 代替”。我试着改用“rowversion”,但还是不行。我也直接在属性上尝试了 TimestampAttribute,但同样的错误。
我试图将时间戳数据放在子类上,但后来我遇到了以下异常
System.Data.Entity.ModelConfiguration.ModelValidationException :一个或多个验证错误是 在模型生成期间检测到
System.Data.Edm.EdmEntityType: : 类型 'Portfolio.Repositories.Drawing' 是 从类型派生 'Portfolio.Repositories.DbEntityBase' 那是 EntitySet 的类型 'PortfolioContext.DbEntityBases'。类型 'Portfolio.Repositories.Drawing' 定义新的并发要求 不允许用于子类型的 基本 EntitySet 类型。
所以我想我也做不到。
我必须说,我很困惑。为什么异常告诉我应该使用时间戳,因为这正是我正在做的?这可能是框架中的错误吗?如果不是,他们是否有任何其他方式来使用 Table PerType 映射添加并发检查?
我使用 SQL Serve Ce 4.0 作为我的数据库。
【问题讨论】:
【参考方案1】:这看起来像是定义 TPC 继承的问题。您必须修改您的子实体映射以使用来自父实体的映射:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
...
modelBuilder.Entity<DrawingVersion>()
.Map(m => m.MapInheritedProperties())
.ToTable("DrawingVersion");
modelBuilder.Entity<Drawing>()
.Map(m => m.MapInheritedProperties())
.ToTable("Drawing");
...
【讨论】:
以上是关于如何在使用 TPT 层次结构时首先在 EF 代码中实现并发的主要内容,如果未能解决你的问题,请参考以下文章
使用 EF Code First 继承 – 每个类型的表 (TPT)
EF Core 5 TPT - 具有不同 ID 名称的继承对象
Inheritance with EF Code First: Part 2 – Table per Type (TPT)