实体框架报告循环引用,但没有任何意义
这是大约。我正在使用的代码。
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
=> 之间生成循环引用。 注释注释
。
EDIT
由于某种原因,将 NoteComment
类中的 FK 指定为可为 null 的属性解决了该问题。
public class NoteComment {
public Guid? UserId { get; set; }
[ForeignKey("UserId")]
public virtual User User { get; set; }
}
然后我删除了数据上下文类中注释掉的映射代码。
这并不理想,但我可以手动管理这个约束。
Here is the approx. code I am working with.
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"));
*/
}
}
}
Note that in the ConfigureNotes()
method, the last configuration is commented out. If I leave this commented out, EF will create my tables just fine, but if I uncomment this block, I get the following error:
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 ---
...
What I don't understand is why the navigation property from NoteComment
=> User
is generating a circular reference between Note
=> NoteComment
.
EDIT
For some reason, specifying the FK in the NoteComment
class as a nullable property fixed the problem.
public class NoteComment {
public Guid? UserId { get; set; }
[ForeignKey("UserId")]
public virtual User User { get; set; }
}
Then I removed the commented out mapping code in the data context class.
This is not ideal, but I can manage this constraint manually.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
与其他数据库相比,SQL Server 对于可能的循环引用或多个删除路径非常保守。
您的问题源自 NoteComment 的多个删除路径:
一种解决方案是删除用户 -> 删除时的级联注意注释并手动进行清理。
您还可以编写数据库触发器来进行清理。这是一个示例触发器:
编辑 - 附加信息:
如果您还没有,我强烈建议 EF 电动工具扩展。这使您能够右键单击任何实现 DbContext 的类并获取实体框架上下文菜单 -
在解决方案资源管理器中右键单击您的 DbContext 类 ->实体框架->查看 DDL SQL
这将为您提供用于生成整个数据模型的 Sql 语句 - 对于了解 EF 认为它正在构建的内容确实非常有用。您可以尝试在 SqlServer 中手动运行它,并更接近它遇到的错误。当 EF 构建 DDL Sql 时,如果没有编译错误,它通常会给您带来一些东西(或者完全神秘的空引用错误 - 然后检查您的输出窗口),但这些东西可能无法在 SqlServer 中运行。
此外,您可以使用流畅配置手动删除删除时的级联,以实现一对多关系,除非您需要该属性,否则无需指定键:
SQL Server is very conservative about possible circular references or multiple delete paths compared to other databases.
Yours is originating from multiple delete paths to NoteComment:
One solution is to remove the Cascade On Delete for User -> NoteComment and do the cleanup manually.
You can also write a database trigger to do the cleanup. Here's an example trigger:
Edits - additional information:
If you don't have it already, I highly suggest the EF Power Tools extension. This gives you the ability to right click on any class implementing DbContext and get the Entity Framework context menu -
Right click your DbContext class in Solution Explorer -> Entity Framework -> View DDL SQL
That will give you the Sql statement used to generate your entire data model - very useful indeed to see what exactly EF thinks it's building. You can try and run it manually in SqlServer and get a bit closer to the errors that it's running into. When EF is building up the DDL Sql, short of compile errors it will usually get you something (or an entirely cryptic null reference error - then check your Output window), but that something might not run in SqlServer.
Also, you can manually remove the cascade on delete for one to many relationships with the fluent configuration, no need to specify keys unless you want that property:
您在“用户”->“注释注释”->“注释”->“用户”->“等等”之间存在循环引用。
您拥有密钥设置后,您将永远不会停止以上述方式进行引用。
有许多不同的方法可以结束循环引用。例如,导致循环引用的属性上方的
[ScriptIgnore]
属性,或者您可以执行树搜索方法,其中每个分支检查以确保添加的对象不是父节点(递归地)一直到树的根节点。You have a circular reference between User->Note Comments->Note->User->etc..
The you have the Keys setup you you will never stop referencing in the above manner.
There are many different methods to end a circular reference. Such as,
[ScriptIgnore]
attribute above the properties that are causing a circular reference, or you can do a tree search method where each branch checks to make sure that the object being added is not a parent node (recursively) all the way to the root node of the tree.