2014-01-12 1 views
1

У меня возникли проблемы с отображением в сущности. У меня есть таблица Check, у которой есть внешний ключ к таблице CheckStatusHistory, где я сохраняю все изменения статуса проверки с течением времени. Как вы можете видеть, Check имеет столбец LastCheckStatusID, который является FK для CheckStatusHistoryID, но таблица CheckStatusHistory также имеет CheckID в качестве столбца FK для CheckID проверки. Идея состоит в том, чтобы сохранить последний CheckStatusHistoryID в чеке, чтобы получить более легко и с лучшей производительностью последний статус проверки. Но также иметь всю историческую информацию.UpdateException Entity framework двунаправленный внешний ключ

Тогда, когда я генерировать Entity Framework сущностей из базы данных я получаю эту схему:

enter image description here

Тот, что его * (от Check) до 1 (CheckStatusHistory), должно быть 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 - это CheckStatusHistory, связанная с LastCheckStatusID.

Но когда я делаю 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: 

Я думаю, что это может быть что-то связанное с наличием 2 FK, один из одной таблицы к другой, а другой из последней таблицы к первому.

Мне нужна помощь.

Я оставляю таблицы SQL здесь:

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]) 
    ) 

ответ

1

Да, это связано с двумя ФКС. EF использует модель для создания порядка команд БД. Он точно не проверяет, какие данные вы установили. Он пытается найти заказ, который будет работать в каждом сценарии - такой порядок не существует в вашем случае, потому что ваша модель позволяет создавать две записи (по одной в каждой таблице), которые будут зависеть друг от друга. В таком случае невозможно вставить их за один проход. На уровне БД вы просто вставляете первый, не зависимый от второго, второй с зависимостью от первого и после этого обновления первый с зависимостью от второго. EF не работает таким образом.

Другие могут не согласиться, но со временем я прихожу к выводу, что таблицы истории работают лучше всего, не ограничивая их различными ссылочными ограничениями. Это, например, позволяет сохранить историю данных, удаленных из основной таблицы. Вам нужен FK из StatusHistory для проверки? Вы все еще можете сохранить CheckID и выполнить ручной запрос Linq, чтобы получить историю проверки, даже если у вас нет FK, но вы потеряете свойство свойства навигации.

+0

Благодарим за ответ! Я решил это раньше, но я думаю, что это может помочь кому-то другому. Я, наконец, закончил делать это за два шага, но внутри транзакции. – Andres