实体框架中的竞争条件

时间:2016-11-11 05:27:18

标签: c# asp.net-mvc entity-framework nullreferenceexception race-condition

我是小型企业的唯一开发人员,我在asp.net mvc应用程序中继承了一些遗留代码,基本上将一个实体从一个业务部门“重新路由”到另一个业务部门。主实体具有“步骤”对象的集合,并且为了实现期望的“重新路由”功能,该动作向该集合添加了几个步骤并设置了其他步骤的属性。这是代码:

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> Re_Route_TIR(int tir_id, double this_step, int group_id, string routing_reason, int re_route_group_id, int selected_opportunity_code, string opportunity_code_comment)
    {
        TIR_OV_Helper helper = new TIR_OV_Helper();

        tir_departments department = db.tir_departments.FirstOrDefault(x => x.department_id == group_id);
        tir_tir_steps currentStep = db.tir_tir_steps.Where(x => x.tir_id == tir_id).OrderBy(x => x.tir_step).FirstOrDefault(x => x.tir_step_date == null);

        try
        {
            var user_id = System.Web.HttpContext.Current.User.Identity.GetUserId();


            tir_tirs tir = db.tir_tirs.FirstOrDefault(x => x.tir_id == tir_id);
            var original_step = tir.steps.OrderBy(x => x.tir_step).FirstOrDefault(o => o.tir_step_date == null);

            original_step.tir_step_date = DateTime.Now;
            original_step.assignedUserId = user_id;
            original_step.tir_step_state_id = 4;

            List<tir_tir_steps> steps = db.tir_tir_steps.Where(x => x.tir_id == tir_id).ToList();
            foreach (tir_tir_steps step in steps)
            {
                if (step.tir_step > original_step.tir_step)
                {
                    step.tir_step += 20;
                }
            }

            tir_tir_steps newstep = new tir_tir_steps();
            tir_tir_steps routedstep = new tir_tir_steps();

            newstep.tir_step = original_step.tir_step + 10;
            newstep.tir_department_id = re_route_group_id;
            newstep.tir_operation_id = 33;
            newstep.tir_step_state_id = 8;
            newstep.tir_id = tir_id;
            newstep.tir_department = db.tir_departments.FirstOrDefault(x => x.department_id == re_route_group_id);

            tir.steps.Add(newstep);

            routedstep.tir_step = newstep.tir_step + 10;
            routedstep.tir_id = tir_id;
            routedstep.tir_department_id = original_step.tir_department_id;
            routedstep.tir_operation_id = original_step.tir_operation_id;
            routedstep.tir_department = db.tir_departments.FirstOrDefault(x => x.department_id == original_step.tir_department_id);

            tir.steps.Add(routedstep);

            helper.SetNextStep(8, tir_id);   // if no resource then 8 = "waiting"


            var previously_with_dept_id = re_route_group_id;
            var currently_with_dept_id = helper.GetCurrentStepGroupId(tir_id); //GetCurrentStepDepartmentId(tir_id);
            tir.current_operation_id = 33; // db.tir_operations.Find(operation_id);
            tir.current_dept_group_id = re_route_group_id;
            tir.currently_with = "Open";

            ////

            tir_tir_opportunity opportunity_code_data = new tir_tir_opportunity
            {
                tir_id = tir_id,
                tir_oppt_id = selected_opportunity_code,
                opptUserId = User.Identity.GetUserId(),
                oppt_report_date = DateTime.Now,
                oppt_report_group_id = department.department_id,
                opp_code_reason = opportunity_code_comment,
                operation = "Re-Route"
            };

            tir_comments dcomment = new tir_comments();
            dcomment.comment_date = DateTime.Now;
            dcomment.comment_user_name = User.Identity.GetFullName();
            dcomment.comment_text = opportunity_code_comment;
            dcomment.department_id = group_id;
            dcomment.department_name = db.tir_departments.SingleOrDefault(x => x.department_id == group_id).department_name;
            dcomment.tir_id = tir_id;

            tir.department_comments.Add(dcomment);
            db.tir_tir_opportunity.Add(opportunity_code_data);
            await db.SaveChangesAsync();

            return RedirectToAction("Index", "Dashboard", new { id = tir_id });
        }

        catch (Exception ex)
        {
            //...
        }
    }

我知道这是一个非常丑陋且漫长的动作,需要重构,但是当我在我的机器上运行它时,它会正常工作。但是,一些测试此代码的用户遇到了空引用异常。这是错误消息:

Error Message - at System.Data.Entity.Core.Objects.DataClasses.RelatedEnd.GetOtherEndOfRelationship(IEntityWrapper wrappedEntity) at System.Data.Entity.Core.Objects.EntityEntry.AddRelationshipDetectedByForeignKey(Dictionary`2 relationships, Dictionary`2 principalRelationships, EntityKey relatedKey, EntityEntry relatedEntry, RelatedEnd relatedEndFrom) at System.Data.Entity.Core.Objects.EntityEntry.DetectChangesInForeignKeys() at System.Data.Entity.Core.Objects.ObjectStateManager.DetectChangesInForeignKeys(IList`1 entries) at System.Data.Entity.Core.Objects.ObjectStateManager.DetectChanges() at System.Data.Entity.Internal.InternalContext.GetStateEntries(Func`2 predicate) at System.Data.Entity.DbContext.GetValidationErrors() at System.Data.Entity.Internal.InternalContext.SaveChangesAsync(CancellationToken cancellationToken) at System.Data.Entity.Internal.LazyInternalContext.SaveChangesAsync(CancellationToken cancellationToken) at System.Data.Entity.DbContext.SaveChangesAsync() at TIR_Sandbox_New.Controllers.LevelCompleteController.<Re_Route_TIR>d__6.MoveNext()

我假设这是Entity Framework中的某种竞争条件,但我对Entity Framework相当新。我认为实体框架中的某些线程没有足够快地完成这些测试人员,这就是为什么它会破坏它们。如何解决问题并使其适用于所有用户?另外,我如何在将来避免类似的问题?任何帮助将不胜感激!

我猜测tirs和步骤之间的关系也可能是相关的,所以我也发布了这些关系。

public class tir_tirs
{
    public tir_tirs()
    {
        this.steps = new HashSet<tir_tir_steps>();
        ...
    }
    public virtual ICollection<tir_tir_steps> steps { get; set; }
}




public class tir_tir_steps
{
    [Key]
    public int tir_steps_id { get; set; }
    public int tir_id { get; set; }

    [ForeignKey("tir_id")]
    public virtual tir_tirs tir { get; set; }
    public Nullable<double> tir_step { get; set; }
    public Nullable<System.DateTime> tir_step_date { get; set; }
    public int? tir_step_state_id { get; set; }

    [ForeignKey("tir_step_state_id")]
    public virtual tir_steps_status tir_step_state { get; set; }

}

0 个答案:

没有答案