2015-08-29 4 views
1

У меня такая же ошибка, как один сообщается на переполнение стека: EntityFramework's AddOrUpdate leads to incorrect foreign key updateAddOrUpdate приводит к неправильному внешнего ключа обновления

Keeping кратки, после того как я называю AddOrUpdate, чтобы вставить новую запись, если я затем вызвать AddOrUpdate обновить одна и та же запись, она выдает исключение.

Пример:

State.cs 
int Id; 
string Name; 

City.cs 
int Id; 
int StateId; 
string Name; 
int Location; 

// Crud 
var state = new State { Name = "NY" }; 
Context.States.AddOrUpdate(p => p.Name, state); 
Context.SaveChanges(); 

// Adds with location equals to 1 
var city = new City { Name = "NYC", Location = "1", State = state }; 
Context.Cities.AddOrUpdate(p => p.Name, city); 
Context.SaveChanges(); 

// Updating the location to 2, leads to EF trying to set StateId to 0 
var city = new City { Name = "NYC", Location = "2", State = state }; 
Context.Cities.AddOrUpdate(p => p.Name, city); 
Context.SaveChanges(); 

исключение, говоря внешний ключ StateId = 0

Стек следа:

"The UPDATE statement conflicted with the FOREIGN KEY constraint "FK_dbo.City_dbo.State_StateId". The conflict occurred in database "C:\X\APP_DATA\LOCAL.MDF", table "dbo.State", column 'Id'. 
The statement has been terminated." 

System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction) 
System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction) 
System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) 
System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) 
System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString) 
System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, SqlDataReader ds, Boolean describeParameterEncryptionRequest) 
System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean asyncWrite) 
System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, String methodName, Boolean sendToPipe, Int32 timeout, Boolean asyncWrite) 
System.Data.SqlClient.SqlCommand.ExecuteNonQuery() 
System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.<NonQuery>b__0(DbCommand t, DbCommandInterceptionContext`1 c) 
System.Data.Entity.Infrastructure.Interception.InternalDispatcher`1.Dispatch[TTarget,TInterceptionContext,TResult](TTarget target, Func`3 operation, TInterceptionContext interceptionContext, Action`3 executing, Action`3 executed) 
System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.NonQuery(DbCommand command, DbCommandInterceptionContext interceptionContext) 
System.Data.Entity.Internal.InterceptableDbCommand.ExecuteNonQuery() 
System.Data.Entity.Core.Mapping.Update.Internal.DynamicUpdateCommand.Execute(Dictionary`2 identifierValues, List`1 generatedValues) 
System.Data.Entity.Core.Mapping.Update.Internal.UpdateTranslator.Update() 

БЛАГОДАРЯ

+0

Можете ли вы добавить коды для классов сущностей, пожалуйста? –

+0

Пожалуйста, укажите полное исключение и стек. – Aron

+0

Вы пытались использовать 'StateId = state.StateId' вместо' State = state' там? – JohnnyHK

ответ

2

AddOrUpdate предназначен только для простого высева операций , В некоторых сценариях это know to be buggy, и это тоже должно быть ошибкой. Это неожиданное поведение.

Вероятно, это связано с тем, как значения свойств копируются из предоставленного экземпляра (ваша переменная city) в экземпляр, извлеченный из базы данных. Ясно, что учитываются только примитивные свойства.

После того, как ваше заявление ...

var city = new City { Name = "NYC", Location = "2", State = state }; 

... city будет StateId = 0. Этого это значение, которое присваивается экземпляр базы данных (который является другим экземпляром, чем city).

Как только вы осознаете это, вы можете исправить это, установив StateId вместо State.

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

Но, как правило, если вы хотите обновить объект, очень вероятно, что вы уже его загрузили, а затем обновили его в каком-то процессе и теперь хотите отправить его снова. Даже в приложениях N-уровня (с сериализации/десериализации и т. Д.) У вас, вероятно, все еще есть идентификатор объекта, с помощью которого вы можете определить, следует ли его вставлять или обновлять. Поэтому в большинстве случаев вы можете обойтись без повторной выборки сущности из базы данных, а AddOrUpdate всегда будет делать это, если она существует.

Смежные вопросы