none
Обновление данных в связанных таблицах ADO.NET Entity Framework RRS feed

  • Вопрос

  • Подскажите пожалуйста. Есть 2 таблицы со связью  один ко многим. Используется MS SQL и ADO.NET Entity Framework. Возникает проблема при каскадном обновлении связанных полей между таблицами. При этом удаление строк происходит нормально. При изменении первичного ключа возникает ошибка о том, что первичный ключ изменять нельзя. Почему ? И где находятся настройки, изменяющий этот параметр ? При изменении внешнего ключа ошибка возникает при вызове метода SaveChanges()  объекта типа ObjectContext. Каким образом нужно правильно обновлять связанные данные втаблицах? Спасибо.

    14 февраля 2011 г. 20:55

Ответы

  • Давайте рассмотрим реакцию SQL Server на каскадное обновление ключей.

     

    use tempdb
    go
    
    create table t1(t1_id int primary key, t1_value int)
    go
    create table t2(t2_id int identity primary key, t1_id int)
    go
    create table t3(t3_id int identity primary key, t2_id int)
    go
    
    alter table [dbo].[t2]
    with check add constraint [FK_t2_t1]
    foreign key([t1_id])
    references [t1] ([t1_id]) on update cascade on delete cascade 
    go
    
    alter table [dbo].[t3]
    with check add constraint [FK_t3_t2]
    foreign key([t2_id])
    references [t2] ([t2_id]) on update cascade on delete cascade 
    go
    
    insert into t1 values(1, 1)
    go
    insert into t2 values((select top 1 t1_id from t1 where t1_value = 1))
    go
    insert into t3 values((select top 1 t2_id from t2 where t1_id = (select top 1 t1_id from t1 where t1_value = 1)))
    go
    
    -- Вы можете обновить первичный ключ, т.к. 
    -- значение в колонку t1_id было вставлено явно.
    update t1 set t1_id = 12345 where t1_id = (select top 1 t1_id from t1 where t1_value = 1)
    go
    
    -- Вы не можете выполнить следующий update, 
    -- т.к. поле t2_id определено как identity и не может быть актуализировано.
    -- Для вставки удаленных значений из колонки со свойством identity
    -- используйте параметр set identity_insert on
    update t2 set t2_id = 12345 where t1_id = (select top 1 t1_id from t1 where t1_value = 1)
    go
    
    select * from t1
    select * from t2
    select * from t3
    go
    
    alter table t2 drop constraint FK_t2_t1
    go
    alter table t3 drop constraint FK_t3_t2
    go
    drop table t1, t2, t3
    go
    

     

    • Помечено в качестве ответа Abolmasov Dmitry 17 февраля 2011 г. 6:06
    15 февраля 2011 г. 22:07
  • Подскажите пожалуйста. Есть 2 таблицы со связью  один ко многим. Используется MS SQL и ADO.NET Entity Framework. Возникает проблема при каскадном обновлении связанных полей между таблицами. При этом удаление строк происходит нормально. При изменении первичного ключа возникает ошибка о том, что первичный ключ изменять нельзя. Почему ? И где находятся настройки, изменяющий этот параметр ? При изменении внешнего ключа ошибка возникает при вызове метода SaveChanges()  объекта типа ObjectContext. Каким образом нужно правильно обновлять связанные данные втаблицах? Спасибо.


    1) "При изменении первичного ключа возникает ошибка о том, что первичный ключ изменять нельзя." - на сколько мне известно это действительно так и относится к этому нужно как одной из особенностей EF. Кстати использовал MS SQL и ADO.NET Entity Framework в паре крупных коммерческих проектах (500-600 таблиц) и ни разу не возникала такая потребность!


    2) "При изменении внешнего ключа ошибка возникает при вызове метода SaveChanges()  объекта типа ObjectContext." - внешний ключ менять не нужно! Пример того как нужно использовать EF для изменения внешнего ключа:
     

    using (Model1Container mc = new Model1Container())
       {
        // Создание записей
        ParentEntity pe1 = new ParentEntity() { Value = "ParentEntity1" };
        mc.ParentEntity.AddObject(pe1); // Добавление нового объекта ParentEntity
        
        ParentEntity pe2 = new ParentEntity() { Value = "ParentEntity1" };
        mc.ParentEntity.AddObject(pe2); // Добавление нового объекта ParentEntity
    
        ChildEntity ch1 = new ChildEntity() { Value = "ChildEntity1" };
        pe1.ChildEntity.Add(ch1); // Проставляем связь ChildEntity с ParentEntity
        mc.ChildEntity.AddObject(ch1); // Добавление нового объекта ChildEntity
    
        ChildEntity ch2 = new ChildEntity() { Value = "ChildEntity2" };
        pe2.ChildEntity.Add(ch2); // Проставляем связь ChildEntity с ParentEntity
        mc.ChildEntity.AddObject(ch2); // Добавление нового объекта ChildEntity
    
        mc.SaveChanges(); // Сохраняем данные
    
        // Меняем связи 
        pe1.ChildEntity.Remove(ch1);
        pe2.ChildEntity.Remove(ch2);
    
        pe1.ChildEntity.Add(ch2);
        pe2.ChildEntity.Add(ch1);
    
        mc.SaveChanges(); // Сохраняем данные
       };
    
    • Предложено в качестве ответа DenisX555 20 февраля 2011 г. 13:22
    • Помечено в качестве ответа Abolmasov Dmitry 21 февраля 2011 г. 11:58
    19 февраля 2011 г. 19:55

Все ответы

  • Давайте рассмотрим реакцию SQL Server на каскадное обновление ключей.

     

    use tempdb
    go
    
    create table t1(t1_id int primary key, t1_value int)
    go
    create table t2(t2_id int identity primary key, t1_id int)
    go
    create table t3(t3_id int identity primary key, t2_id int)
    go
    
    alter table [dbo].[t2]
    with check add constraint [FK_t2_t1]
    foreign key([t1_id])
    references [t1] ([t1_id]) on update cascade on delete cascade 
    go
    
    alter table [dbo].[t3]
    with check add constraint [FK_t3_t2]
    foreign key([t2_id])
    references [t2] ([t2_id]) on update cascade on delete cascade 
    go
    
    insert into t1 values(1, 1)
    go
    insert into t2 values((select top 1 t1_id from t1 where t1_value = 1))
    go
    insert into t3 values((select top 1 t2_id from t2 where t1_id = (select top 1 t1_id from t1 where t1_value = 1)))
    go
    
    -- Вы можете обновить первичный ключ, т.к. 
    -- значение в колонку t1_id было вставлено явно.
    update t1 set t1_id = 12345 where t1_id = (select top 1 t1_id from t1 where t1_value = 1)
    go
    
    -- Вы не можете выполнить следующий update, 
    -- т.к. поле t2_id определено как identity и не может быть актуализировано.
    -- Для вставки удаленных значений из колонки со свойством identity
    -- используйте параметр set identity_insert on
    update t2 set t2_id = 12345 where t1_id = (select top 1 t1_id from t1 where t1_value = 1)
    go
    
    select * from t1
    select * from t2
    select * from t3
    go
    
    alter table t2 drop constraint FK_t2_t1
    go
    alter table t3 drop constraint FK_t3_t2
    go
    drop table t1, t2, t3
    go
    

     

    • Помечено в качестве ответа Abolmasov Dmitry 17 февраля 2011 г. 6:06
    15 февраля 2011 г. 22:07
  • Подскажите пожалуйста. Есть 2 таблицы со связью  один ко многим. Используется MS SQL и ADO.NET Entity Framework. Возникает проблема при каскадном обновлении связанных полей между таблицами. При этом удаление строк происходит нормально. При изменении первичного ключа возникает ошибка о том, что первичный ключ изменять нельзя. Почему ? И где находятся настройки, изменяющий этот параметр ? При изменении внешнего ключа ошибка возникает при вызове метода SaveChanges()  объекта типа ObjectContext. Каким образом нужно правильно обновлять связанные данные втаблицах? Спасибо.


    1) "При изменении первичного ключа возникает ошибка о том, что первичный ключ изменять нельзя." - на сколько мне известно это действительно так и относится к этому нужно как одной из особенностей EF. Кстати использовал MS SQL и ADO.NET Entity Framework в паре крупных коммерческих проектах (500-600 таблиц) и ни разу не возникала такая потребность!


    2) "При изменении внешнего ключа ошибка возникает при вызове метода SaveChanges()  объекта типа ObjectContext." - внешний ключ менять не нужно! Пример того как нужно использовать EF для изменения внешнего ключа:
     

    using (Model1Container mc = new Model1Container())
       {
        // Создание записей
        ParentEntity pe1 = new ParentEntity() { Value = "ParentEntity1" };
        mc.ParentEntity.AddObject(pe1); // Добавление нового объекта ParentEntity
        
        ParentEntity pe2 = new ParentEntity() { Value = "ParentEntity1" };
        mc.ParentEntity.AddObject(pe2); // Добавление нового объекта ParentEntity
    
        ChildEntity ch1 = new ChildEntity() { Value = "ChildEntity1" };
        pe1.ChildEntity.Add(ch1); // Проставляем связь ChildEntity с ParentEntity
        mc.ChildEntity.AddObject(ch1); // Добавление нового объекта ChildEntity
    
        ChildEntity ch2 = new ChildEntity() { Value = "ChildEntity2" };
        pe2.ChildEntity.Add(ch2); // Проставляем связь ChildEntity с ParentEntity
        mc.ChildEntity.AddObject(ch2); // Добавление нового объекта ChildEntity
    
        mc.SaveChanges(); // Сохраняем данные
    
        // Меняем связи 
        pe1.ChildEntity.Remove(ch1);
        pe2.ChildEntity.Remove(ch2);
    
        pe1.ChildEntity.Add(ch2);
        pe2.ChildEntity.Add(ch1);
    
        mc.SaveChanges(); // Сохраняем данные
       };
    
    • Предложено в качестве ответа DenisX555 20 февраля 2011 г. 13:22
    • Помечено в качестве ответа Abolmasov Dmitry 21 февраля 2011 г. 11:58
    19 февраля 2011 г. 19:55
  • Спасибо. Можно ещё один вопрос.  Можно ли из кода EntityFramework или мастеров Visual Studio установить ограничение unique для отдельного поля таблицы? Или в случае с ADO.NET EntityFramework это ограничение должно быть физически установлено в самой базе MS SQL ?
    20 февраля 2011 г. 11:03
  • Спасибо. Можно ещё один вопрос.  Можно ли из кода EntityFramework или мастеров Visual Studio установить ограничение unique для отдельного поля таблицы? Или в случае с ADO.NET EntityFramework это ограничение должно быть физически установлено в самой базе MS SQL ?

    Делать это конечно же нужно "в самой базе MS SQL".
    20 февраля 2011 г. 13:20