Entity Framework 报告循环引用,但没有任何意义
Posted
技术标签:
【中文标题】Entity Framework 报告循环引用,但没有任何意义【英文标题】:Entity Framework reports circular reference, but it doesn't make any sense 【发布时间】:2012-01-23 19:42:07 【问题描述】:这是大约。我正在使用的代码。
public class Note
public virtual Customer Customer get; set;
public virtual User User get; set;
public ICollection<NoteComment> Comments get; set;
public class NoteComment
public virtual User User get; set;
public class User
public ICollection<Note> Notes get; set;
public class Customer
// --------------------------------------
public class OurDataContext
private void ConfigureNotes(DbModelBuilder modelBuilder)
modelBuilder.Entity<Note>()
.HasRequired<User>(n => n.User)
.WithMany(u => u.Notes)
.Map(a => a.MapKey("UserId"));
modelBuilder.Entity<Note>()
.HasRequired(n => n.Customer)
.WithMany(c => c.Notes)
.Map(a => a.MapKey("idCustomer"));
modelBuilder.Entity<Note>()
.HasMany(n => n.Comments)
.WithRequired()
.HasForeignKey(c => c.NoteID);
/*
modelBuilder.Entity<NoteComment>()
.HasRequired<User>(c => c.User)
.WithMany()
.Map(a => a.MapKey("UserId"));
*/
注意ConfigureNotes()
方法中,最后的配置被注释掉了。如果我将此注释掉,EF 会很好地创建我的表,但如果我取消注释此块,我会收到以下错误:
Unhandled Exception: System.InvalidOperationException: The database creation succeeded, but the creation of the database objects did not. See inner exception for more details. ---> System.Data.SqlServerCe.SqlCeException: The referential relationship will result in a cyclical reference that is not allowed. [ Constraint name = Note_Comments ]
at System.Data.SqlServerCe.SqlCeCommand.ProcessResults(Int32 hr)
at System.Data.SqlServerCe.SqlCeCommand.ExecuteCommandText(IntPtr& pCursor, Boolean& isBaseTableCursor)
at System.Data.SqlServerCe.SqlCeCommand.ExecuteCommand(CommandBehavior behavior, String method, ResultSetOptions options)
at System.Data.SqlServerCe.SqlCeCommand.ExecuteNonQuery()
at System.Data.SqlServerCe.SqlCeProviderServices.DbCreateDatabase(DbConnection connection, Nullable`1 timeOut, StoreItemCollection storeItemCollection)
--- End of inner exception stack trace ---
...
我不明白为什么NoteComment
=> User
的导航属性在Note
=> NoteComment
之间生成循环引用。
EDIT
由于某种原因,将 NoteComment
类中的 FK 指定为可为空的属性解决了该问题。
public class NoteComment
public Guid? UserId get; set;
[ForeignKey("UserId")]
public virtual User User get; set;
然后我删除了数据上下文类中被注释掉的映射代码。
这并不理想,但我可以手动管理这个约束。
【问题讨论】:
【参考方案1】:与其他数据库相比,SQL Server 对于可能的循环引用或多个删除路径非常保守。
您的来自 NoteComment 的多个删除路径:
Delete User -> Note -> NoteComment
Delete User -> NoteComment
一种解决方案是删除 Cascade On Delete for User -> NoteComment 并手动进行清理。
您还可以编写数据库触发器来进行清理。这是一个示例触发器:
CREATE TRIGGER [dbo].[Users_Delete_Cleanup]
ON [dbo].[Users]
INSTEAD OF DELETE
AS
BEGIN
IF @@ROWCOUNT = 0
RETURN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Delete NoteComment <--> User associations
DELETE nc FROM [dbo].[NoteComment] nc
JOIN DELETED dUser ON dUser.[Id] = nc.[User_Id]
-- Finally, delete user
DELETE u
FROM DELETED dUser
JOIN [dbo].[Users] u ON u.[Id] = dUser.[Id]
END
编辑 - 附加信息:
如果您还没有,我强烈建议您使用EF Power Tools extension。这使您能够右键单击任何实现 DbContext 的类并获取实体框架上下文菜单 - 在解决方案资源管理器中右键单击您的 DbContext 类 -> 实体框架 -> 查看 DDL SQL
这将为您提供用于生成整个数据模型的 Sql 语句 - 对于查看 EF 认为它正在构建的确切内容非常有用。您可以尝试在 SqlServer 中手动运行它,并更接近它所遇到的错误。当 EF 构建 DDL Sql 时,如果没有编译错误,它通常会给你一些东西(或者一个完全神秘的空引用错误 - 然后检查你的输出窗口),但这些东西可能不会在 SqlServer 中运行。
此外,您可以手动删除级联删除与流畅配置的一对多关系,除非您想要该属性,否则无需指定键:
modelBuilder.Entity<NoteComment>()
.HasRequired<User>(c => c.User)
.WithMany()
.WillCascadeOnDelete(false);
【讨论】:
好的,但仍然对此感到困惑的是,如果我注释掉映射代码,EF 仍然会从 NoteComments => User 生成自己的 FK,但它使用属性名称 User_ID,这就是我正在尝试使用手动映射进行更改。如果 SQL Server 在级联删除方面存在问题,为什么它会允许 EF 生成这种关系? 这是一个 EF CodeFirst 约定 - 在模型生成过程中根本不涉及 SqlServer。 EF 会自行生成架构,而不管 SqlServer 是否接受它。当您手动将键指定为可为空的类型时,将删除删除时的级联。【参考方案2】:您在 User->Note Comments->Note->User->etc..之间有一个循环引用。
如果您有 Keys 设置,您将永远不会停止以上述方式引用。
有许多不同的方法可以结束循环引用。例如,[ScriptIgnore]
属性在导致循环引用的属性上方,或者您可以执行树搜索方法,其中每个分支检查以确保添加的对象不是父节点(递归地)一直到树的根节点。
【讨论】:
以上是关于Entity Framework 报告循环引用,但没有任何意义的主要内容,如果未能解决你的问题,请参考以下文章
Entity Framework Core 5 - 在表上引入 FOREIGN KEY 约束可能会导致循环或多个级联路径
在 Entity Framework 6 查询中取消引用可能为空的引用
Entity Framework Core 2 - 外键约束
在 Entity Framework 7 中创建自引用多对多关系