我有两个类:项目和schedulePhases之间有1到多个关系。我试图从SchedulePhases集合中删除阶段。但它会在SaveChanges()上抛出异常。
例外:
发生了错误。操作失败:无法更改关系,因为一个或多个外键属性不可为空。当对关系进行更改时,相关的外键属性将设置为空值。如果外键不支持空值,则必须定义新关系,必须为外键属性分配另一个非空值,或者必须删除不相关的对象。 System.Data.Entity.Core.Objects.ObjectContext.d__31.MoveNext()中System.Data.Entity.Core.Objects.ObjectContext.PrepareToSaveChanges(SaveOptions选项)的System.InvalidOperationException ---来自上一个位置的堆栈跟踪结束在System.Runtime.CompilerServices.TaskAwaiter({1}}的System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务)的System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务任务)处抛出异常1.GetResult ()at System.Threading.Tasks.TaskHelpersExtensions.d__3 1.GetResult() at AddProjectODataService.Controllers.ProjectsController.<Patch>d__a.MoveNext() in c:\Workspace\VS2013\POC\AddProjectODataService\AddProjectODataService\Controllers\ProjectsController.cs:line 142 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter
1.GetResult()at System.Web.Http.Controllers.ApiControllerActionInvoker.d__0.MoveNext()---从前一个位置开始的堆栈跟踪异常抛出了---在System.Runtime.Compiler服务.TaskAwaiter.ThrowForNonSuccess(任务任务)的System.Runtime.Compiler服务.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务)System.Runtime.CompilerServices.TaskAwaiter 1.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter
1.GetResult( )在System.Web.Http.Dispatcher.H上ttpControllerDispatcher.d__1.MoveNext()
Project.cs:
1.GetResult() at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__2.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter
SchedulePhase.cs:
public class Project
{
public Project()
{
SchedulePhases = new HashSet<SchedulePhase>();
}
public void Initialize()
{
CalculateSchedule();
}
[Key]
public decimal ProjectId { get; set; }
public decimal AssetId { get; set; }
public decimal CapitalCategoryId { get; set; }
public decimal ProjectTypeId { get; set; }
public virtual Asset Asset { get; set; }
public virtual ICollection<SchedulePhase> SchedulePhases { get; set; }
public virtual CapitalCategory CapitalCategory { get; set; }
public virtual ProjectType ProjectType { get; set; }
public void CalculateSchedule()
{
List<SchedulePhase> SchedulePhaseList = new List<SchedulePhase>();
SchedulePhase sp = new SchedulePhase();
if (this.ProjectTypeId == 15)
{
if (this.SchedulePhases.Count > 0)
{
foreach (SchedulePhase phase in SchedulePhases.ToList())
{
SchedulePhases.Remove(phase);
}
}
}
}
这是我在ProjectController.cs中的补丁操作(我正在使用带有web api的Odata V3):
public class SchedulePhase
{
public SchedulePhase()
{
}
[Key]
public decimal SchedulePhaseId { get; set; }
public decimal ProjectId { get; set; } //FK
public decimal PhaseTypeId { get; set; }
public DateTime StartDate { get; set; }
[StringLength(1)]
public string ActualEstimateCalcStart { get; set; }
public DateTime EndDate { get; set; }
[StringLength(1)]
public string ActualEstimateCalcEnd { get; set; }
public decimal Duration { get; set; }
public decimal? CostingYear { get; set; }
public decimal? Cost { get; set; }
public decimal OffSet { get; set; }
public virtual Project Project { get; set; }
public virtual PhaseType PhaseType { get; set; }
}
我已阅读了一些文章,但不确定在我的方案中要解决的问题。
我参考了以下文章: http://blogs.msdn.com/b/dsimmons/archive/2010/01/31/deleting-foreign-key-relationships-in-ef4.aspx http://msdn.microsoft.com/en-us/data/jj713564.aspx Entity Framework .Remove() vs. .DeleteObject()(在此,用户建议使用DeleteObject显式删除子节点。我正在使用DbContext。)
有什么建议吗?
谢谢,
答案 0 :(得分:0)
试图告诉您的异常是您在Project和SchedulePhase对象之间存在依赖关系(由SchedulePhase类的ProejctId属性表示)。
当您调用Project.SchedulePhases.Remove时,EF会尝试切断两个对象之间的关系,而不会实际删除子(SchedulePhase)对象。它通过尝试将外键属性(在本例中为ProjectId)的值设置为null来实现此目的。由于属性的值(在这种情况下为十进制)是不可为空的,因此EF不知道该怎么做。它期望您将ProjectId属性的值更改为指向另一个Project实例。
执行DeleteObject或其DbContext对应(记住DbContext只是ObjectContext最常用方法的包装)实际上从数据库中删除了SchedulePhase对象。
几年前,EF团队的Arthur Vickers在他的博客上写了一篇很好的文章here,更详细地解释了这个例外。它甚至包括一些用于自动删除相关实体的代码,但我永远无法使其工作。