使用EF6从集合中删除项目(1对多关系)

时间:2014-11-19 21:52:09

标签: asp.net entity-framework

我有两个类:项目和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。)

有什么建议吗?

谢谢,

1 个答案:

答案 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,更详细地解释了这个例外。它甚至包括一些用于自动删除相关实体的代码,但我永远无法使其工作。

相关问题