我正在尝试使用已在UI中更改的独立关联更新对象。加载和保存在不同的DBContexts中进行。我尝试了以下,但现在我被卡住了。我偶尔会遇到DBUpdateExceptions。
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.
据我所知,这源于现有对象之间的现有关系,这些关系由Entity Framework添加并且未包含在导航属性中,并且在绘制状态时我没有设置为Unchanged。但是如何识别它们呢?
这就是我到目前为止所做的:
以下是代码:
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
我正在使用Entity Framework 6.0.1和Visual Studio 2013。
对我来说,出现了以下问题:
我是Entity Framework的新手。所以我的问题可能有一个简单的解决方案。
提前多多感谢。