我在 WPF 应用程序中将 EF5 与 DbContext 和 Database-First 方法一起使用,并在以下场景中删除实体和使用所需的数据注释属性时遇到了一些逻辑问题:
这是两个用外键相互引用的表,没有级联删除:
|----A----| |----B----|
|ID int |<-| |ID int |
|---------| |-|A_ID int |
因此,如果某些“B”引用“A”,则不能删除“A”。
EF 5 模型包括关联,并且 - 由于没有设置级联 - OnDelete 设置为“无”到关联的两端。我已经用 [Required] 属性装饰了“A_ID”字段和导航属性“BA”——当我删除一个“A”实体时,我的麻烦就开始了,其中“B”实体引用了这个“A”实体:
MyContext.Set<A>().Remove(MyA);
MyContext.SaveChanges();
SaveChanges 将“B”的所有导航属性设置为已删除的“A”实体为空。这会使“B”无效,因为导航属性具有必需的属性抛出异常,即“A”不能被删除,因为“B”无效 - 这在某种程度上是一个奇怪的原因。
但是,在删除 Navigation 属性上的 Required-Attribute 并将 Required-Attribute 保留在 B.A_ID 属性上之后,会引发正确的错误。
最后,在数据库异常之后,我最终得到一个对象图,其中“A”的所有导航属性都设置为“null”。
我认为这是 EF 的预期行为,但这会导致两个问题:
首先,删除操作无效。我还没有找到任何关于“删除”验证的信息。数据注释仅考虑属性更改。
其次,由于所有导航属性都设置为“null”,因此如何在异常后恢复已删除的实体。EF 5 关联不如允许关联上“无”、“设置为 NULL”或“级联”的 SQL Server 关联精确。在“无”的情况下,SQL Server 抛出异常,使所有实体保持不变。
如果有人在数据库异常后遇到“CanDelete”验证和实体恢复的相同问题并有解决方案或可以将我指向其他相关线程,请告诉我。
你的,
马库斯
示例类:
// Entity to delete
public partial class A {
public A() {
this.Bs = new HashSet<B>();
}
public int ID { get; set; }
public Nullable<int> C_ID { get; set; }
public string Name { get; set; }
public virtual C C { get; set; }
public virtual ICollection<B> Bs { get; set; }
}
// Child entities of A with foreign key constraint
public partial class B {
public int ID { get; set; }
public int A_ID { get; set; }
public string Name { get; set; }
public virtual A A { get; set; }
}
// Example class of an additional entity referencing A
public partial class C {
public C() {
this.As = new HashSet<A>();
}
public int ID { get; set; }
public string Name { get; set; }
public virtual ICollection<A> As { get; set; }
}
数据库架构:
CREATE DATABASE [EFABC]
GO
USE [EFABC]
GO
CREATE TABLE [dbo].[tA](
[ID] [int] IDENTITY(1,1) NOT NULL,
[C_ID] [int] NULL,
[Name] [nvarchar](50) NULL,
CONSTRAINT [PK_tA] PRIMARY KEY CLUSTERED
(
[ID] ASC
) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[tB](
[ID] [int] IDENTITY(1,1) NOT NULL,
[A_ID] [int] NOT NULL,
[Name] [nvarchar](50) NULL,
CONSTRAINT [PK_tB] PRIMARY KEY CLUSTERED
(
[ID] ASC
) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[tC](
[ID] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](50) NULL,
CONSTRAINT [PK_tC] PRIMARY KEY CLUSTERED
(
[ID] ASC
) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[tA] WITH CHECK ADD CONSTRAINT [FK_tA_tC] FOREIGN KEY([C_ID])
REFERENCES [dbo].[tC] ([ID])
GO
ALTER TABLE [dbo].[tA] CHECK CONSTRAINT [FK_tA_tC]
GO
ALTER TABLE [dbo].[tB] WITH CHECK ADD CONSTRAINT [FK_tB_tA] FOREIGN KEY([A_ID])
REFERENCES [dbo].[tA] ([ID])
GO
ALTER TABLE [dbo].[tB] CHECK CONSTRAINT [FK_tB_tA]
GO