gpt4 book ai didi

c# - 无法删除具有所需父属性的 ef 实体

转载 作者:行者123 更新时间:2023-11-30 16:59:41 26 4
gpt4 key购买 nike

我对 EF 不是很满意,所以这可能很简单。

我有

    public void DeleteLicense(int licenseId)
{
var entityToDelete = context.Licenses.Find(licenseId);
context.Licenses.Remove(entityToDelete);
}

我检查过它找到了正确的许可证,上下文是一个 ninject(每个请求一个)DbContext,

但是当我在运行上面的函数后在上下文中调用 SaveChanges() 时,我得到了一个奇怪的错误。我得到:“CustomerName 字段是必需的。

现在这很奇怪,因为 CustomerName 在帐户(而不是许可证)中,它们是链接的,但仍然。所以这里还有一些:

我的帐户实体

[Required]
public String CustomerName { get; set; }

public virtual ICollection<License> Licenses { get; set; }
...

我的许可证实体

public virtual Account Account { get; set; }
...

我的流畅设置

modelBuilder.Entity<Account>().HasMany(x => x.Licenses)
.WithRequired(x => x.Account).WillCascadeOnDelete(false);

我不明白,因为即使约束失败了,为什么还缺少 CustomerName。当我删除许可证时,我没有触及 CustomerName,并且 CustomerName 是以前设置的。

更新

下面是代码中的更多细节。据我所知,完整的执行路径是

下面的

DeleteLicenseAPI 接受调用,ID 正确,它传递给私有(private)函数。私有(private)函数调用靠近问题顶部显示的 DeleteLicenseCommit() 仅调用 context.SaveChanges();

public ActionResult DeleteLicenseAPI(int licenseId)
{
if (DeleteLicense(licenseId))
{
return Content("ok");
}

return Content("[[[Failed to delete license]]]");

}

private bool DeleteLicense(int licenseId)
{
//todo: sort out busniess rules for delete, is cascaded?
_accountRepository.DeleteLicense(licenseId);
_accountRepository.Commit();

return true;
}

_accountRepository 看起来像这样

public class EFAccountRepository : EntityFrameworkRepository<Account>
, IAccountRepository

public EFAccountRepository(EvercateContext context) : base(context)
{
}

这里是 Ninject 中的代码,用于设置这一切

kernel.Bind<EvercateContext>()
.To<EvercateContext>()
.InRequestScope()
.WithConstructorArgument("connectionStringOrName", "EvercateConnection");


kernel.Bind<IAccountRepository>().To<EFAccountRepository>();

因此,即使我在运行 SaveChanges 之前,据我所知(并且不应该)使用工作单元,也不会在此请求中调用任何其他内容。有什么方法可以查看 DbContext 将在 SaveChanges 上做什么,而无需实际运行该方法(因为它会抛出 DbEntityValidationException)

最佳答案

我可以想象,如果您像这样在 License 构造函数中初始化 Account 导航属性,可能会发生这种奇怪的异常:

public License
{
Account = new Account();
}

调用时的流程...

var entityToDelete = context.Licenses.Find(licenseId);
context.Licenses.Remove(entityToDelete);

...那么可能是:

  • License 实体被加载(没有导航属性 Account)并附加到上下文(状态 Unchanged)
  • 构造函数设置了 Account 导航属性,但它没有被附加(状态 Detached)
  • 当您为 License 实体调用 Remove 时,EF 在内部调用了 DetectChanges。它检测到 License.Account 正在引用一个分离的实体并将其附加到上下文(处于 Added 状态)。 License 的状态更改为 Deleted
  • 当您调用 SaveChanges 时,更改跟踪器发现两个实体:状态为 DeletedLicenseAccount处于状态已添加
  • 验证运行并发现应该插入到数据库中的实体 Account 所需的属性 CustomerNamenull(因为仅调用 Account 的默认构造函数。
  • 抛出验证异常。

我不确定细节是否正确,但类似的事情可能正在发生。

在任何情况下,您都应该从 License 构造函数中删除 Account = new Account(); 并检查您是否初始化了其他reference代码库中实体构造函数中的导航属性也是如此。 (初始化空导航 集合 是可以的。)这是众所周知的奇怪问题的常见来源,很难找到和理解。

关于c# - 无法删除具有所需父属性的 ef 实体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23450208/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com