【发布时间】:2014-04-01 15:33:36
【问题描述】:
此解决方案涉及三个实体,Client、Competency 和 WeaponType。
-
Client实例可以在List<Competency>成员中拥有零个或多个Competency实例。 -
Competency实例可以在List<WeaponType>成员中拥有一个或多个WeaponType实例。 (WeaponType是我们的查找成员)
在更新 DbContext 之前,会为客户端分配一个新的 List 对象。这代表了客户能力的完整更新列表,其中旧能力可能已被删除并创建新能力。
遇到的问题是 dbContext.SaveChanges() 会导致创建重复的 WeaponType 条目。
这是我的实体的代码:
public class Client : Person
{
public ICollection<CompetencyCertificate> CompetencyCertificates
{
get;
set;
}
}
public class CompetencyCertificate
{
public Int64 Id { get; set; }
[Required]
public string CertificateNumber { get; set; }
[Required]
public List<WeaponType> CompetencyTypes { get; set; }
}
public class WeaponType
{
public Int16 Id { get; set; }
[Required]
public string Name { get; set; }
}
以及用于保存我更新的客户和能力信息的代码(这也反映了我克服这个问题的尝试:
private void SaveClientProfile()
{
HttpRequestBase rb = this.Request;
string sId = "";
if (rb.Form["Id"] != null)
sId = rb.Form["Id"];
Int64 int64_id = 0;
if (sId.Trim().Length > 0)
int64_id = Int64.Parse(sId);
Client client = loadOrCreateClient(int64_id);
//Set the newly submitted form data for the client
client.IDSocialSecurityPassNum = rb.Form["IDNumber"];
client.EmailAddress = rb.Form["EmailAddress"];
client.NickName = rb.Form["Name"];
client.Surname = rb.Form["Surname"];
//MAP AND TRANSLATE JSON COLLECTION OBJECTS TO ENTITY COLLECTIONS, UPDATE THE CONTEXT
Mapper.CreateMap<Client_Competency_ViewModel, CompetencyCertificate>();
client.CompetencyCertificates = Mapper.Map<List<CompetencyCertificate>>(System.Web.Helpers.Json.Decode<System.Collections.Generic.List<Client_Competency_ViewModel>>(rb.Form["CompetencyCollection"]));
//PREVENT EF FROM DUPLICATING LOOKUP VALUES
AttachLookup<WeaponType>(JCGunsDb.WeaponTypes.ToList<WeaponType>());
//FNIALISE AND SAVE
dbContext.UserId = User.Identity.GetUserName();
dbContext.SaveChanges();
}
private void AttachLookup<T>(ICollection<T> itemsToAttach) where T : class
{
foreach(T item in itemsToAttach)
{
JCGunsDb.Entry(item).State = EntityState.Unchanged;
}
}
我可以确认上述代码中的 JSON 解析和映射按预期工作 - 现有实体的 Id 完好无损,新实体 Id 设置为 0。
我在做什么导致这种行为?我该如何解决?
更新: 根据 Gert 的建议,我尝试使用 GraphDiff 实现一个解决方案(这似乎完全符合我的要求)。但是,我正在努力让它发挥作用。这是我所做的(根据提出的 Github 问题):
我有以下几点:
客户 客户 >> 列出能力证书 CompetencyCertificate >> 列出 CompetencyTypes
我从数据库中加载一个客户端对象,然后将新的 List 值分配给上面提到的 List 成员。
随后,我调用以下代码:
dbContext.UpdateGraph(client, map => map
.OwnedCollection(cc => cc.CompetencyCertificates, with => with
.AssociatedCollection(kt => kt.CompetencyTypes))
);
dbContext.SaveChanges();
以下是在 UpdateGraph 调用中引发的异常的堆栈跟踪:
无法为类型实体调用成员“CurrentValues” 'CompetencyCertificate',因为实体不存在于 语境。要将实体添加到上下文中,请调用 Add 或 Attach 方法 数据库集。
描述:执行过程中发生了未处理的异常 当前的网络请求。请查看堆栈跟踪以获取更多信息 有关错误的信息以及它在代码中的来源。
异常详细信息:System.InvalidOperationException:成员 不能为类型的实体调用“CurrentValues” 'CompetencyCertificate',因为实体不存在于 语境。要将实体添加到上下文中,请调用 Add 或 Attach 方法 数据库集。
来源错误:
第 138 行:第 139 行://更新分离实体的图表 第 140 行:dbContext.UpdateGraph(client, map => map Line 141:.OwnedCollection(cc => cc.CompetencyCertificates, 使用 => 使用第 142 行:.AssociatedCollection(kt => kt.CompetencyTypes))
源文件:[不重要]行:140
堆栈跟踪:
[InvalidOperationException:无法调用成员“CurrentValues” 对于“CompetencyCertificate”类型的实体,因为该实体确实 上下文中不存在。要将实体添加到上下文中,请调用 Add 或 DbSet 的 Attach 方法。]
System.Data.Entity.Internal.InternalEntityEntry.ValidateNotDetachedAndInitializeRelatedEnd(字符串 方法)+102
System.Data.Entity.Internal.InternalEntityEntry.ValidateStateToGetValues(字符串 方法,EntityState 无效状态)+55
System.Data.Entity.Internal.InternalEntityEntry.get_CurrentValues() +53 System.Data.Entity.Infrastructure.DbEntityEntry.get_CurrentValues() +44 RefactorThis.GraphDiff.DbContextExtensions.RecursiveGraphUpdate(DbContext 上下文、对象数据存储实体、对象更新实体、更新成员 会员)+942
RefactorThis.GraphDiff.DbContextExtensions.UpdateGraph(DbContext 上下文,T 实体,表达式1 mapping) +6312 个参数)+435
JCGunsOnline.Controllers.ClientController.SaveClientProfile() in c:\Users\Ben\Dropbox\Mighty IT\Active Projects\JCGunsOnline\JCGunsOnline\Views\Client\ClientController.cs:140 JCGunsOnline.Controllers.ClientController.SubmitStep1() in c:\Users\Ben\Dropbox\Mighty IT\Active Projects\JCGunsOnline\JCGunsOnline\Views\Client\ClientController.cs:60 lambda_method(Closure , ControllerBase , Object[] ) +101
System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters) +59
System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary
System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary2 parameters) +602.CallEndDelegate(IAsyncResult asyncResult) +73
System.Web.Mvc.Async.ActionInvocation.InvokeSynchronousActionMethod() +76 System.Web.Mvc.Async.AsyncControllerActionInvoker.<BeginInvokeSynchronousActionMethod>b__39(IAsyncResult asyncResult, ActionInvocation innerInvokeState) +36
System.Web.Mvc.Async.WrappedAsyncResult
System.Web.Mvc.Async.WrappedAsyncResultBase1.End() +1361.CallEndDelegate(IAsyncResult asyncResult) +47
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +102
System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult) +49
System.Web.Mvc.Async.AsyncInvocationWithFilters.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3f() +117 System.Web.Mvc.Async.<>c__DisplayClass48.<InvokeActionMethodFilterAsynchronouslyRecursive>b__41() +323 System.Web.Mvc.Async.<>c__DisplayClass33.<BeginInvokeActionMethodWithFilters>b__32(IAsyncResult asyncResult) +44
System.Web.Mvc.Async.WrappedAsyncResult
System.Web.Mvc.Async.WrappedAsyncResultBase1.End() +1361.CallEndDelegate(IAsyncResult asyncResult) +42
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +102
System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethodWithFilters(IAsyncResult asyncResult) +50
System.Web.Mvc.Async.<>c__DisplayClass2b.<BeginInvokeAction>b__1c() +72 System.Web.Mvc.Async.<>c__DisplayClass21.<BeginInvokeAction>b__1e(IAsyncResult asyncResult) +185
System.Web.Mvc.Async.WrappedAsyncResult
System.Web.Mvc.Async.WrappedAsyncResultBase1.End() +1331.CallEndDelegate(IAsyncResult asyncResult) +70
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +56
System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeAction(IAsyncResult asyncResult) +40
System.Web.Mvc.Controller.<BeginExecuteCore>b__1d(IAsyncResult asyncResult, ExecuteCoreState innerState) +34
System.Web.Mvc.Async.WrappedAsyncVoid
System.Web.Mvc.Async.WrappedAsyncResultBase1.End() +1391.CallEndDelegate(IAsyncResult asyncResult) +62
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +59
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +40
System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) +44 System.Web.Mvc.Controller.<BeginExecute>b__15(IAsyncResult asyncResult, Controller controller) +39
System.Web.Mvc.Async.WrappedAsyncVoid
System.Web.Mvc.Async.WrappedAsyncResultBase1.End() +1391.CallEndDelegate(IAsyncResult asyncResult) +70
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +59
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +40 System.Web.Mvc.Controller.EndExecute(IAsyncResult asyncResult) +39
System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.EndExecute(IAsyncResult asyncResult) +39
System.Web.Mvc.MvcHandler.<BeginProcessRequest>b__5(IAsyncResult asyncResult, ProcessRequestState innerState) +39
System.Web.Mvc.Async.WrappedAsyncVoid
System.Web.Mvc.Async.WrappedAsyncResultBase`1.End() +139
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, 对象标签)+59
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, 对象标签)+40
System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +40 System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult 结果)+38
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +9514928 System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155
【问题讨论】:
标签: c# asp.net-mvc orm entity-framework-6