由于外键关系而导致的System.Data.SqlClient.SqlException显然不在查询中

时间:2012-04-19 03:38:09

标签: linq-to-sql

概述

这是一个奇怪的错误,没有用Google搜索。

我尝试创建并插入AssetOwner记录。但我收到错误" System.Data.SqlClient.SqlException"由于两个表上的外键关系(显然)与我尝试的SQL语句无关:

  

INSERT语句与FOREIGN KEY约束冲突   " FK_Adjustments_AdjustmentProcesses&#34 ;.冲突发生在   数据库" TPS_2",表" dbo.AdjustmentProcesses",列' ID'。该   声明已被终止。

详细信息

以下是抛出错误的代码段(由注释指示)(" da"就像存储库一样):

var add = new AssetOwner()
{
   Client = da.Clients.Get(adjustment.ToClientID),
   Asset = da.Assets.Get(adjustment.AssetID),
   StartDate = adjustment.EffectiveDate
};
da.AssetOwners.Add(add);

var remove = da.AssetOwners.GetCurrentOwner(da.Assets.Get(adjustment.AssetID));
remove.EndDate = adjustment.EffectiveDate;
da.SaveChanges(); // Exception here (this is DataContext.SubmitChanges())

这里有关于表格和关系的小图片:

enter image description here

抛出错误的关系已突出显示为红色,有问题的表格已用红色圈出 - 如您所见,AssetOwner的插入内容似乎与调整调整过程关系无关?

疑难解答

我使用Visual Studio生成的LINQ-to-SQL类,有时我在DataContext的刷新版本中注意到了奇怪的gremlins。因此,我的第一个想法是删除有问题的关系,重新生成,重新创建关系,重新生成。这没有成功。

我已经完成了几次代码 - 值得注意的是,在此代码之前控制器操作中没有其他SQL语句 - 我无法看到任何可能的原因导致此异常。不过,我将在这里重现整个控制器动作(希望长代码片段不会阻止任何潜在的读者):

public ActionResult ManualEntry(int id, FormCollection collection)
    {
        // Grab the adjustment process
        var process = da.AdjustmentProcesses.Get(id);

        // Map a dto and set the details needed for the view
        var dto = new AdjustmentProcessViewModel();
        Adapter.MapDto(dto, process, da);
        Adapter.SetDetails(dto, da);

        // Generate the premium values for those policies we can
        var pg = new PremiumGenerator(da);
        foreach (var apd in dto.AdjustmentPolicyDetails)
        {
            if (apd.CanAutoGenerate == true)
                pg.GeneratePremiumValues(dto.Policies[apd.Index]);
        }

        // Update the model from the form collection
        TryUpdateModel(dto.Policies, "Policies");

        // Run Validation
        var invalids = 0;
        foreach (var apd in dto.AdjustmentPolicyDetails)
        {
            var policy = dto.Policies[apd.Index];
            var validator = new PolicyValidator(da);
            validator.Validate(policy);
            if (!validator.IsValid)
            {
                invalids++;
                foreach (var ruleViolation in validator.RuleViolations)
                    apd.RuleViolations.Add(new RuleViolation(ruleViolation.ErrorMessage, "Policies[" + apd.Index.ToString() + "]." + ruleViolation.PropertyName));
                this.MergeRuleViolations(apd.RuleViolations);
            }
        }

        // If validation has failed, return the view
        if (invalids > 0)
            return View(dto);
        else // Otherwise process the adjustments
        {
            foreach (var adjustment in da.Adjustments.GetAdjustmentsForProcess(process.ID))
            {
                if (adjustment.ActionID == (int)AdjustmentAction.Add)
                {
                    var add = new AssetOwner()
                    {
                        Client = da.Clients.Get(adjustment.ClientID),
                        Asset = da.Assets.Get(adjustment.AssetID),
                        StartDate = adjustment.EffectiveDate
                    };
                    da.AssetOwners.Add(add);
                    da.SaveChanges();
                }
                else if (adjustment.ActionID == (int)AdjustmentAction.Remove)
                {
                    var remove = da.AssetOwners.GetCurrentOwner(da.Assets.Get(adjustment.AssetID));
                    remove.EndDate = adjustment.EffectiveDate;
                    da.SaveChanges();
                }
                else if (adjustment.ActionID == (int)AdjustmentAction.Transfer)
                {
                    var add = new AssetOwner()
                    {
                        Client = da.Clients.Get(adjustment.ToClientID),
                        Asset = da.Assets.Get(adjustment.AssetID),
                        StartDate = adjustment.EffectiveDate
                    };
                    da.AssetOwners.Add(add);

                    var remove = da.AssetOwners.GetCurrentOwner(da.Assets.Get(adjustment.AssetID));
                    remove.EndDate = adjustment.EffectiveDate;
                    da.SaveChanges();
                }
            }

            var policyAdapter = new PolicyAdapter();
            foreach (var policy in dto.Policies)
            {
                var newPolicy = new Policy();
                policyAdapter.MapObject(newPolicy, policy, da);
                var validator = new PolicyValidator(da);
                validator.Validate(newPolicy);
                if (!validator.IsValid)
                    throw new Exception();
                else
                {
                    da.Policies.Add(newPolicy);
                    da.SaveChanges();
                }
            }
        }

        return RedirectToAction("Index");
    }

也许一个线索是我正在研究的对象是"转移" (沿着那个代码路径)抛出错误,而"添加"或"删除"两者都工作正常而不会抛出错误。尽管如此,代码实际上是相同的,并且DB表中的所有调整对象都满足外键约束。

为了进一步帮助排除故障,这里是堆栈跟踪:

  

System.Data.SqlClient.SqlException(0x80131904):INSERT语句   与FOREIGN KEY约束冲突   " FK_Adjustments_AdjustmentProcesses&#34 ;.冲突发生在   数据库" TPS_2",表" dbo.AdjustmentProcesses",列' ID'。该   声明已经终止。在   System.Data.SqlClient.SqlConnection.OnError(SqlException异常,   Boolean breakConnection)at   System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning()at   System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior,   SqlCommand cmdHandler,SqlDataReader dataStream,   BulkCopySimpleResultSet bulkCopyHandler,TdsParserStateObject   System.Data.SqlClient.SqlDataReader.ConsumeMetaData()中的stateObj)   在System.Data.SqlClient.SqlDataReader.get_MetaData()at   System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds,   RunBehavior runBehavior,String resetOptionsString)at   System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(的CommandBehavior   cmdBehavior,RunBehavior runBehavior,Boolean returnStream,Boolean   async)at   System.Data.SqlClient.SqlCommand.RunExecuteReader(的CommandBehavior   cmdBehavior,RunBehavior runBehavior,Boolean returnStream,String   方法,DbAsyncResult结果)at   System.Data.SqlClient.SqlCommand.RunExecuteReader(的CommandBehavior   cmdBehavior,RunBehavior runBehavior,Boolean returnStream,String   方法)at   System.Data.SqlClient.SqlCommand.ExecuteReader(的CommandBehavior   行为,String方法)at   System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(的CommandBehavior   行为)   System.Data.Linq.SqlClient.SqlProvider.Execute(表达式查询,   QueryInfo queryInfo,IObjectReaderFactory factory,Object []   parentArgs,Object [] userArgs,ICompiledSubQuery [] subQueries,Object   lastResult)at   System.Data.Linq.SqlClient.SqlProvider.ExecuteAll(表达式查询,   QueryInfo [] queryInfos,IObjectReaderFactory factory,Object []   userArguments,ICompiledSubQuery [] subQueries)at   System.Data.Linq.SqlClient.SqlProvider.System.Data.Linq.Provider.IProvider.Execute(表达式   查询)   System.Data.Linq.ChangeDirector.StandardChangeDirector.DynamicInsert(TrackedObject   项目)   System.Data.Linq.ChangeDirector.StandardChangeDirector.Insert(TrackedObject   项目)   System.Data.Linq.ChangeProcessor.SubmitChanges(ConflictMode   failureMode)at   System.Data.Linq.DataContext.SubmitChanges(ConflictMode failureMode)
  在TPS.Models.TPSDataAccess.SaveChanges()中   C:\ Users \ tim.niven.KJRG \ Documents \ Visual Studio   2010 \项目\ TPS-干线\ TPS \ TPS \型号\ MainObjects \ TPSDataAccess.cs:行   169 at   TPS.Areas.Clients.Controllers.AdjustmentProcessController.ManualEntry(的Int32   id,FormCollection集合)   C:\ Users \ tim.niven.KJRG \ Documents \ Visual Studio   2010 \项目\ TPS-干线\ TPS \ TPS \区\ CLIENTS \ \控制器AdjustmentProcessController.cs:行   257在lambda_method(Closure,ControllerBase,Object [])at   System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext   controllerContext,IDictionary 2 parameters) at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary 2   参数)at   System.Web.Mvc.ControllerActionInvoker<> c__DisplayClass15.b__12()   在   System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter   filter,ActionExecutingContext preContext,Func 1 continuation) at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodWithFilters(ControllerContext controllerContext, IList 1个过滤器,ActionDescriptor actionDescriptor,   IDictionary`2参数)at   System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext   controllerContext,String actionName)

所以我整天都在用桌子敲打我的头 - 任何帮助或指导将不胜感激。

干杯,

1 个答案:

答案 0 :(得分:1)

最终它很愚蠢(因为它经常是这样):它当然是动作中的其他一些代码,其中一个适配器方法是操作从数据库中检索到的对象,它不应该是

一旦我隔离了抛出异常的代码,并且它起了作用,我改变了事物的顺序,发现异常不是在AssetOwner的插入上抛出的。因此,我在整个代码中的多个位置调用了DataContext.SubmitChanges(),以找出导致问题的位置 - 找到并修复。