下面是使用 EF5 代码优先方法的最简化形式的情况:
public abstract class EntityBase<PK>
{
public PK ID { get; set; }
}
public class Country : EntityBase<string>
{
public string Name { get; set; }
}
public class Address : EntityBase<int>
{
[Required]
public string CountryID { get; set; }
public Country Country { get; set; }
// ... other address properties ...
}
Address
和之间的一对多关系Country
是在没有级联删除的情况下设置的,如下所示:
modelBuilder.Entity<Address>()
.HasRequired(a => a.Country)
.WithMany()
.HasForeignKey(a => a.CountryID)
.WillCascadeOnDelete(false);
最后,我有一个通用的基础存储库类,其中包含调用SaveChanges
底层 DbContext 以原子方式提交数据更改的 CRUD 方法。例如:
public class EFRepository<T, PK> : IRepository<T, PK> where T : EntityBase<PK>
{
//
// ... other methods ...
//
public virtual void Delete(T instance)
{
// ... trigger validations, write to log, etc...
_dbContext.Set<T>().Remove(instance);
try
{
_dbContext.SaveChanges();
}
catch(Exception ex)
{
// ... handle the error ...
}
}
}
第1部分:
设想:
var countryRepo = new EFRepository<Country>();
var country = countryRepo.Save(new Country() { ID="??", Name="Test Country" });
var addressRepo = new EFRepository<Address>();
var address = addressRepo.Save(new Address() { Country=country });
countryRepo.Delete(country);
由于存在依赖项,这应该会失败Address
。但是,之后地址以 null in 结束CountryID
,这是无效的,因为Address.CountryID
它是必需的,因此后续SaveChanges
调用会引发验证异常,除非地址被分离。
我希望当一个对象被删除时,EF5 将足够聪明地首先检查任何像上面那样的级联删除约束,如果找不到任何约束,然后继续删除数据。但情况似乎恰恰相反。
这是正常行为还是我做错了什么?
第2部分:
SaveChanges
在调用失败后,一些Addresses
现在在我的 DbContext 中处于无效状态,需要恢复到它们的原始值。当然,我总是可以通过创建专门的存储库类和覆盖来为每种实体类型(Country
、State
、Order
等)明确地这样做Delete
,但它闻起来很香。我更愿意编写一些通用代码来在 SaveChanges
调用失败后优雅地恢复相关实体。
它将需要询问 DbContext 以获取其中一个实体(例如Country
)是主体的所有关系,而不管其类是否定义了依赖实体的导航属性。
egCountry
没有Addresses
属性,所以我需要以某种方式在 DbContext 中找到 and 之间的一对多关系的定义,Country
并Address
使用它来恢复Addresses
与其原始值相关的所有内容。
这可能吗?