C# UpdateException实体框架双向外键

C# UpdateException实体框架双向外键,c#,sql-server-2008-r2,entity-framework-6,C#,Sql Server 2008 R2,Entity Framework 6,我在实体框架中的映射方面遇到了一些问题。我有一个表Check,它有一个表CheckStatusHistory的外键,我在其中存储了所有检查状态随时间的变化。如您所见,Check有一个列LastCheckStatusID,它是一个FK到CHECKSTATUSSHISTORYID,但表CHECKSTATUSHORY也有一个CheckID作为Check的FK到CheckID列。 这样做的目的是将last CheckStatusHistoryID存储在支票中,以便更轻松、更高效地获取last check

我在实体框架中的映射方面遇到了一些问题。我有一个表Check,它有一个表CheckStatusHistory的外键,我在其中存储了所有检查状态随时间的变化。如您所见,Check有一个列LastCheckStatusID,它是一个FK到CHECKSTATUSSHISTORYID,但表CHECKSTATUSHORY也有一个CheckID作为Check的FK到CheckID列。 这样做的目的是将last CheckStatusHistoryID存储在支票中,以便更轻松、更高效地获取last check状态。而且,还要有所有的历史信息

然后,当我从数据库生成实体框架实体时,我得到以下图表:

其*(从检查)到1(检查状态历史记录)的值应为1到1。但由于EF的限制,这是不可能的

然后,在我的代码中,当我想创建一个带有状态历史记录的支票时,我会:

Check newCheck = new Check
                {
                    Amount = c.Amount,
                    CheckDate = c.CheckDate,
                    CheckNumber = c.CheckNumber,
                    CheckPrefix = c.CheckPrefix,
                    Days = c.Days,
                    Expenses = c.Expenses,
                    RoutingNumbers = c.RoutingNumbers,
                    TradeHours = c.TradeHours,
                    TotalInterest = c.TotalInterest,
                    TentativeDepositDate = c.TentativeDepositDate,
                    TentativeAccreditationDate = c.TentativeAccreditationDate,
                    MonthlyRate = c.MonthlyRate
                };

newCheck.CheckStatusHistory = new CheckStatusHistory
                {
                    CheckStatusID = CheckStatusIDs.Nuevo,
                    StatusDateTime = DateTime.Now,
                };
这应该是在[CheckStatusHistory]中添加一行。此newCheck.CheckStatusHistory是与LastCheckStatusID相关的CheckStatusHistory

但是当我执行db.SaveChanges()时

我得到以下错误:

System.Data.Entity.Infrastructure.DbUpdateException was unhandled by user code
  HResult=-2146233087
  Message=Unable to determine a valid ordering for dependent operations. Dependencies may exist due to foreign key constraints, model requirements, or store-generated values.
  Source=EntityFramework
  StackTrace:
       en System.Data.Entity.Internal.InternalContext.SaveChanges()
       en System.Data.Entity.Internal.LazyInternalContext.SaveChanges()
       en System.Data.Entity.DbContext.SaveChanges()
       en Plutus.Services.Check.CreateOperationHandler.Handle(CreateOperationRequest request) en e:\Plutus\Plutus.Services\Plutus.Services\Check\CreateOperationHandler.cs:línea 169
       en Plutus.Services.RequestResponse.RequestResponseFactory.Handle[TRequest,TResponse](TRequest request) en e:\Plutus\Plutus.Services\Plutus.Services\RequestResponse\RequestResponseFactory.cs:línea 48
       en Plutus.Services.Host.CheckService.CreateOperation(CreateOperationRequest request) en e:\Plutus\Plutus.Services\Plutus.Services.Host\CheckService.svc.cs:línea 50
       en SyncInvokeCreateOperation(Object , Object[] , Object[] )
       en System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
       en System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
  InnerException: System.Data.Entity.Core.UpdateException
       HResult=-2146233087
       Message=Unable to determine a valid ordering for dependent operations. Dependencies may exist due to foreign key constraints, model requirements, or store-generated values.
       Source=EntityFramework
       StackTrace:
            en System.Data.Entity.Core.Mapping.Update.Internal.UpdateTranslator.DependencyOrderingError(IEnumerable`1 remainder)
            en System.Data.Entity.Core.Mapping.Update.Internal.UpdateTranslator.ProduceCommands()
            en System.Data.Entity.Core.Mapping.Update.Internal.UpdateTranslator.Update()
            en System.Data.Entity.Core.EntityClient.Internal.EntityAdapter.<Update>b__2(UpdateTranslator ut)
            en System.Data.Entity.Core.EntityClient.Internal.EntityAdapter.Update[T](T noChangesResult, Func`2 updateFunction, Boolean throwOnClosedConnection)
            en System.Data.Entity.Core.EntityClient.Internal.EntityAdapter.Update(Boolean throwOnClosedConnection)
            en System.Data.Entity.Core.Objects.ObjectContext.<SaveChangesToStore>b__33()
            en System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction[T](Func`1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess)
            en System.Data.Entity.Core.Objects.ObjectContext.SaveChangesToStore(SaveOptions options, IDbExecutionStrategy executionStrategy)
            en System.Data.Entity.Core.Objects.ObjectContext.<>c__DisplayClass28.<SaveChanges>b__25()
            en System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func`1 operation)
            en System.Data.Entity.Core.Objects.ObjectContext.SaveChanges(SaveOptions options)
            en System.Data.Entity.Internal.InternalContext.SaveChanges()
       InnerException: 

是的,它与两个FK有关。EF使用该模型创建DB命令的顺序。它不会精确检查您设置的数据。它试图找到一种在每种情况下都有效的排序方式——这种排序方式在您的案例中并不存在,因为您的模型允许创建两条相互依赖的记录(每个表中一条记录)。在这种情况下,不可能一次插入它们。在DB级别,您只需将第一个没有依赖关系的插入到第二个,第二个有依赖关系的插入到第一个,然后将第一个有依赖关系的插入到第二个。EF不是这样工作的


其他人可能不同意,但随着时间的推移,我得出结论,历史表格在不受不同引用约束的情况下效果最好。例如,它允许保留从主表中删除的数据的历史记录。是否需要StatusHistory中的FK进行检查?即使没有FK,您仍然可以存储CheckID并执行手动Linq查询以获取历史记录以进行检查,但您将失去导航属性。

谢谢您的回答!我以前解决过这个问题,但我认为这可以帮助其他人。我最终通过两个步骤完成了这项工作,但都是在一个事务中完成的。
CREATE TABLE [dbo].[Check](
        [CheckID] INT PRIMARY KEY IDENTITY NOT NULL,
        [RoutingNumbers] NCHAR(29) NOT NULL,
        [BankID] INT NOT NULL, --FK
        [BankBranchOfficeID] INT NOT NULL, -- FK
        [BankAccountID] INT NOT NULL,
        [CheckPrefix] NVARCHAR(3) NOT NULL,
        [CheckNumber] NCHAR(7) NOT NULL,
        [CheckDate] DATE NOT NULL,
        [Amount] MONEY NOT NULL,
        [TentativeDepositDate] DATE NOT NULL,
        [TradeHours] INT NOT NULL,
        [TentativeAccreditationDate] DATE NOT NULL,
        [Expenses] MONEY NULL,
        [MonthlyRate] DECIMAL (6,2) NOT NULL,
        [TotalInterest] MONEY NOT NULL,
        [Days] INT NOT NULL,
        [LastCheckStatusID] INT NOT NULL,
        [OperationID] INT NOT NULL,--FK
        CONSTRAINT FK_Check_BankID_Bank FOREIGN KEY ([BankID]) REFERENCES [dbo].[Bank]([BankID]),
        CONSTRAINT FK_Check_BankBranchOfficeID_BankBranchOffice FOREIGN KEY ([BankBranchOfficeID]) REFERENCES [dbo].[BankBranchOffice]([BankBranchOfficeID]),
        CONSTRAINT FK_Check_BankAccountID_BankAccount FOREIGN KEY ([BankAccountID]) REFERENCES [dbo].[BankAccount]([BankAccountID]),
        CONSTRAINT FK_Check_CheckStatusHistoryID_CheckStatusHistory FOREIGN KEY (LastCheckStatusID) REFERENCES [dbo].[CheckStatusHistory]([CheckStatusHistoryID]),
        CONSTRAINT FK_Check_OperationID_Operation FOREIGN KEY ([OperationID]) REFERENCES [dbo].[Operation]([OperationID])
        )

    /*---------------------------------------------------------------
        ESTADO DE CHEQUES
    */---------------------------------------------------------------
    CREATE TABLE [dbo].CheckStatus(
        [CheckStatusID] TINYINT PRIMARY KEY,
        [Name] NVARCHAR(30) NOT NULL 
    )

    /*---------------------------------------------------------------
        RELACION ESTADO - CHEQUE
    */---------------------------------------------------------------

        CREATE TABLE [dbo].[CheckStatusHistory](
        [CheckStatusHistoryID] INT PRIMARY KEY IDENTITY,
        [CheckStatusID] TINYINT NOT NULL, --FK
        [CheckID] INT NOT NULL,
        [StatusDateTime] DATETIME NOT NULL
        CONSTRAINT FK_CheckStatusHistory_CheckID_Check FOREIGN KEY ([CheckID]) REFERENCES [dbo].[Check]([CheckID]),
        CONSTRAINT FK_CheckStatusHistory_CheckStatusID_CheckStatus FOREIGN KEY ([CheckStatusID]) REFERENCES [dbo].[CheckStatus]([CheckStatusID])
    )