Entity framework 实体框架:如何在断开连接的场景中更新具有独立关联的实体?
我正在尝试更新一个具有独立关联的对象,该关联已在UI中更改。加载和保存在不同的DBContext中进行。我试过以下方法,但现在我被卡住了。我时不时地遇到DbUpdateExceptionEntity framework 实体框架:如何在断开连接的场景中更新具有独立关联的实体?,entity-framework,Entity Framework,我正在尝试更新一个具有独立关联的对象,该关联已在UI中更改。加载和保存在不同的DBContext中进行。我试过以下方法,但现在我被卡住了。我时不时地遇到DbUpdateException EFTestConsole.UserList.Update: System.Data.Entity.Infrastructure.DbUpdateException: An error occurred while saving entities that do not expose foreign key p
EFTestConsole.UserList.Update: System.Data.Entity.Infrastructure.DbUpdateException: An error occurred while saving entities that do not expose foreign key properties for their relationships. The EntityEntries property will return null because a single entity cannot be identified as the source of the exception. Handling of exceptions while saving can be made easier by exposing foreign key properties in your entity types. See the InnerException for details. ---> System.Data.Entity.Core.OptimisticConcurrencyException: Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries.
就我所见,这源于现有对象之间的现有关系,这些对象是由实体框架添加的,不包含在导航属性中,并且在绘制状态时我没有将其设置为“未更改”。但如何识别它们呢
这就是我到目前为止所做的:
Public Function Update(ByVal userToProcess As User) As Boolean
Dim Success As Boolean = False
' Compute, which objects in the navigation properties were added resp. removed.
' Register userToProcess in TempDBContext.
TempDBContext.UserDBSet.Add(userToProcess)
TempDBContext.Entry(userToProcess).State = EntityState.Modified
' Fixing relationships to objects in navigation properties in 3 steps:
' 1. Deleting relationships to objects, which remain in database.
For Each adg As ADGroup In UsersADGroupsToDelete
If TempDBContext.Entry(adg).State = EntityState.Detached Then
adg = TempDBContext.ADGroupDBSet.Find(adg.ID)
TempDBContext.Entry(adg).State = EntityState.Unchanged
End If
TempDBContext.Core.ObjectStateManager _
.ChangeRelationshipState( _
userToProcess, _
adg, _
"UsersADGroupsList", _
EntityState.Deleted)
Next
For Each ug As Group In UsersGroupsToDelete
If TempDBContext.Entry(ug).State = EntityState.Detached Then
ug = TempDBContext.GroupDBSet.Find(ug.ID)
TempDBContext.Entry(ug).State = EntityState.Unchanged
End If
TempDBContext.Core.ObjectStateManager _
.ChangeRelationshipState( _
userToProcess, _
ug, _
"UsersGroupsList", _
EntityState.Deleted)
Next
' 2.1. Setting objects and relationships to Unchanged for all existing objects in navigation properties.
' 2.2. Settings objects and relationships to Added for all new objects (ID = 0) in naviagtion properties.
For Each adg As ADGroup In userToProcess.UsersADGroupsList
If adg.ID > 0 Then
TempDBContext.Entry(adg).State = EntityState.Unchanged
TempDBContext.Core.ObjectStateManager _
.ChangeRelationshipState( _
userToProcess, _
adg, _
"UsersADGroupsList", _
EntityState.Unchanged)
Else
TempDBContext.Entry(adg).State = EntityState.Added
TempDBContext.Core.ObjectStateManager _
.ChangeRelationshipState( _
userToProcess, _
adg, _
"UsersADGroupsList", _
EntityState.Added)
End If
Next
For Each ug As Group In userToProcess.UsersGroupsList
If ug.ID > 0 Then
TempDBContext.Entry(ug).State = EntityState.Unchanged
TempDBContext.Core.ObjectStateManager _
.ChangeRelationshipState( _
userToProcess, _
ug, _
"UsersGroupsList", _
EntityState.Unchanged)
Else
TempDBContext.Entry(ug).State = EntityState.Added
TempDBContext.Core.ObjectStateManager _
.ChangeRelationshipState( _
userToProcess, _
ug, _
"UsersGroupsList", _
EntityState.Added)
End If
Next
' 3. Setting objects to Unchanged, which exist in the database, but are newly related to userToProcess.
For Each adg As ADGroup In UsersADGroupsToAdd
If adg.ID > 0 Then
TempDBContext.Entry(adg).State = EntityState.Unchanged
TempDBContext.Core.ObjectStateManager _
.ChangeRelationshipState( _
userToProcess, _
adg, _
"UsersADGroupsList", _
EntityState.Added)
Else
TempDBContext.Entry(adg).State = EntityState.Added
TempDBContext.Core.ObjectStateManager _
.ChangeRelationshipState( _
userToProcess, _
adg, _
"UsersADGroupsList", _
EntityState.Added)
End If
Next
For Each ug As Group In UsersUserGroupsToAdd
If ug.ID > 0 Then
TempDBContext.Entry(ug).State = EntityState.Unchanged
TempDBContext.Core.ObjectStateManager _
.ChangeRelationshipState( _
userToProcess, _
ug, _
"UsersGroupsList", _
EntityState.Added)
Else
TempDBContext.Entry(ug).State = EntityState.Added
TempDBContext.Core.ObjectStateManager _
.ChangeRelationshipState( _
userToProcess, _
ug, _
"UsersGroupsList", _
EntityState.Added)
End If
Next
' EntityFramework adds more objects and relationships to DBContext than are contained within the navigation properties.
' These are to be deleted now.
Dim TempGroupForType As Group = New Group
Dim TempGroupType As System.Type = TempGroupForType.GetType()
Dim TempADGroupForType As ADGroup = New ADGroup
Dim TempADGroupType As System.Type = TempADGroupForType.GetType()
Dim TempUserForType As User = New User
Dim TempUserType As System.Type = TempUserForType.GetType()
For Each e As System.Data.Entity.Infrastructure.DbEntityEntry(Of Modelbase) _
In TempDBContext.ChangeTracker.Entries(Of Modelbase)()
Select Case e.Entity.GetType()
Case TempGroupType
Dim TempGroup As Group = TryCast(e.Entity, Group)
If TempGroup IsNot Nothing _
AndAlso TempGroup.ID > 0 _
AndAlso TempGroup.ParentGroup IsNot Nothing _
AndAlso TempGroup.ParentGroup.ID > 0 Then
' Detach relations to parent groups from DBContext.
TempDBContext.Core.ObjectStateManager _
.ChangeRelationshipState( _
TempGroup, _
TempGroup.ParentGroup, _
"ParentGroup", _
EntityState.Detached)
End If
If e.State = EntityState.Added _
AndAlso TempGroup IsNot Nothing _
AndAlso TempGroup.ID > 0 Then
e.State = EntityState.Detached
End If
Case TempADGroupType
Dim TempADGroup As ADGroup = TryCast(e.Entity, ADGroup)
If e.State = EntityState.Added _
AndAlso TempADGroup IsNot Nothing _
AndAlso TempADGroup.ID > 0 Then
e.State = EntityState.Detached
End If
Case TempUserType
Dim TempUser As User = TryCast(e.Entity, User)
If e.State = EntityState.Added _
AndAlso TempUser IsNot Nothing _
AndAlso TempUser.ID > 0 Then
e.State = EntityState.Detached
End If
End Select
Next
' Save changes to database.
TempDBContext.SaveChanges()
Success = True
End Using
Return Success
End Function
这些对象看起来像这样。存在用户,这些用户可以属于多个组(n:m)。或者,它们可以属于AD组(n:m),并且组和AD组之间可以存在(1:1)关系
Public Class User
Inherits ModelBase
Public Property ID() As Integer
Public Property UserName() As String
' List of AD groups to which the user belongs.
Public Property UsersADGroupsList() As List(Of ADGroup)
' List of groups to which the user belongs.
Public Property UsersGroupsList() As List(Of Group)
Public Sub New()
_UsersADGroupsList = New List(Of ADGroup)
_UsersGroupsList = New List(Of Group)
End Sub
End Class
Public Class ADGroup
Inherits ModelBase
Public Property ID() As Integer
Public Property Name() As String
' List of related users.
Public Property RelatedUsersList() As List(Of User)
' Reference to related group.
Public Property RelatedGroup() As Group
Public Sub New()
_RelatedUsersList = New List(Of User)
End Sub
End Class
Public Class Group
Inherits ModelBase
Public Property ID() As Integer
Public Property Name() As String
' List of related users.
Public Property UserList() As List(Of User)
' Reference to parent group.
Public Property ParentGroup() As Group
' List of children groups.
Public Property ChildrenGroupsList() As List(Of Group)
' Reference to AD group.
Public Property RelatedADGroup As ADGroup
Public Sub New()
_UserList = New List(Of User)
_ChildrenGroupsList = New List(Of Group)
End Sub
End Class
最后,DBContext:
Public Class MyDBContext
Inherits DBContext
' DBSets for the classes below.
Public Property UserDBSet As DbSet(Of User)
Public Property GroupDBSet As DbSet(Of Group)
Public Property ADGroupDBSet As DbSet(Of ADGroup)
' Access to ObjectContext below DBContext.
Private _Core As ObjectContext
Public Property Core() As ObjectContext
Get
Return TryCast(Me, IObjectContextAdapter).ObjectContext
End Get
Private Set(ByVal value As ObjectContext)
_Core = value
End Set
End Property
Public Sub New()
End Sub
Public Sub New(ByVal nameOrConnectionString As String)
MyBase.New(nameOrConnectionString)
End Sub
' Controls the generation of the db model.
Protected Overrides Sub OnModelCreating(modelBuilder As DbModelBuilder)
modelBuilder.Configurations.Add(New ADGroupConfiguration())
modelBuilder.Configurations.Add(New GroupConfiguration())
modelBuilder.Configurations.Add(New UserConfiguration())
End Sub
End Class
Public Class UserConfiguration
Inherits EntityTypeConfiguration(Of User)
Public Sub New()
' Defining optional and required properties.
[Property](Function(u) u.UserName).IsRequired()
' Defining n:m-relationships.
HasMany(Function(u) u.UsersGroupsList).WithMany(Function(g) g.UserList)
End Sub
End Class
Public Class ADGroupConfiguration
Inherits EntityTypeConfiguration(Of ADGroup)
Public Sub New()
' n:m-relationships.
HasMany(Function(a) a.RelatedUsersList).WithMany(Function(u) u.UsersADGroupsList)
End Sub
End Class
Public Class GroupConfiguration
Inherits EntityTypeConfiguration(Of Group)
Public Sub New()
' Defining 1:1-relationships.
HasOptional(Function(g) g.RelatedADGroup).WithOptionalDependent(Function(a) a.RelatedGroup)
' Defining n:m-relationships.
HasMany(Function(g) g.UserList).WithMany(Function(u) u.UsersGroupsList).Map(Sub(t)
t.ToTable("UsersGroups")
End Sub)
End Sub
End Class
我使用的是实体框架6.0.1和Visual Studio 2013
对我来说,出现了以下问题: