【发布时间】:2013-06-04 14:52:37
【问题描述】:
以下是使用 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);
最后,我有一个带有 CRUD 方法的通用基础存储库类,它在底层 DbContext 上调用 SaveChanges 以原子地提交数据更改。例如:
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,这应该会失败。但是,之后地址在CountryID 中以null 结束,这是无效的,因为Address.CountryID 是必需的,因此后续的SaveChanges 调用会抛出验证异常,除非地址被分离。
我希望当一个对象被删除时,EF5 将足够聪明地首先检查任何类似上述的级联删除约束,如果找不到任何约束,然后继续删除数据。但情况似乎恰恰相反。
这是正常行为还是我做错了什么?
第 2 部分:
在SaveChanges 调用失败后,一些Addresses 现在在我的 DbContext 中处于无效状态,需要恢复到它们的原始值。当然,我总是可以通过创建专门的存储库类并覆盖 Delete 来为每种实体类型(Country、State、Order 等)明确地这样做,但它闻起来很香。在SaveChanges 调用失败后,我更愿意编写一些通用代码来优雅地恢复相关实体。
它需要询问 DbContext 以获取其中一个实体(例如 Country)是主体的所有关系,无论其类是否定义了依赖实体的导航属性。
例如Country 没有 Addresses 属性,所以我需要以某种方式在 DbContext 中找到 Country 和 Address 之间的一对多关系的定义,并使用它将所有相关的 Addresses 恢复为其原始值.
这可能吗?
【问题讨论】:
标签: entity-framework entity-framework-5