2015-09-04 6 views
0

Я представляю форму для StoredProcedureReport, которая имеет много StoredProcedureParameters. Создание работает отлично, но попытка обновления оставила меня вопросом, серьезно ли Microsoft серьезно относится к ней.Чистое обновление иерархии в Entity Framework

Я пришел из фона Rails, где @report.update_attributes(params[:report]) точно знает, что делать с любыми данными ассоциации, которые он находит. Из того, что я могу сказать, эквивалент .NET это TryUpdateModel, который выглядел многообещающим. Во-первых. Так что я попытался его с некоторым Params как этого

IDGUID:d70008a5-a1a3-03d2-7baa-e39c5044ad41 
StoredProcedureName:GetUsers 
Name:search again UPDATED 
StoredProcedureReportParameters[0].IDGUID:d70008a5-aba3-7560-a6ef-30a5524fac72 
StoredProcedureReportParameters[0].StoredProcedureReportID:d70008a5-a1a3-03d2-7baa-e39c5044ad41 
StoredProcedureReportParameters[0].Name:RowsPerPage 
StoredProcedureReportParameters[0].Label:rows 
StoredProcedureReportParameters[0].StoredProcedureReportParameterDataTypeID:a50008a5-2755-54c0-b052-865abf459f7f 
StoredProcedureReportParameters[0].StoredProcedureReportParameterInputTypeID:a50008a5-2955-a593-d00f-00cd4543babf 
StoredProcedureReportParameters[0].DefaultValue:10 
StoredProcedureReportParameters[0].AllowMultiple:false 
StoredProcedureReportParameters[0].Hidden:false 
StoredProcedureReportParameters[1].IDGUID:d70008a5-a7a3-e35e-28b6-36dd9e448ee5 
StoredProcedureReportParameters[1].StoredProcedureReportID:d70008a5-a1a3-03d2-7baa-e39c5044ad41 
StoredProcedureReportParameters[1].Name:PageNumber 
StoredProcedureReportParameters[1].Label:page was MODIFIEIIEIEIED!!! 
StoredProcedureReportParameters[1].StoredProcedureReportParameterDataTypeID:a50008a5-2755-54c0-b052-865abf459f7f 
StoredProcedureReportParameters[1].StoredProcedureReportParameterInputTypeID:a50008a5-2955-a593-d00f-00cd4543babf 
StoredProcedureReportParameters[1].DefaultValue:1 
StoredProcedureReportParameters[1].AllowMultiple:false 
StoredProcedureReportParameters[1].Hidden:false 

я предположил, что с установить все первичные и внешние ключи, EF будет знать, как обновить StoredProcedureReportParameter объектов, когда я делаю это:

var report = context.StoredProcedureReports.FirstOrDefault(r => r.IDGUID == reportID); 

if (report != null) 
{ 
    succeeded = TryUpdateModel(report); 
    context.SaveChanges(); 
} 

сейчас , если я установил точку останова на context.SaveChanges(), мой объект report и связанный с ним StoredProcedureReportParameters выглядят так, как я ожидал. Установлены внешние и первичные ключи, ВСЕ значения проверяются. Но SaveChanges поднимает эту ошибку:

The operation failed: The relationship could not be changed because one or more of the foreign-key properties is non-nullable. When a change is made to a relationship, the related foreign-key property is set to a null value. If the foreign-key does not support null values, a new relationship must be defined, the foreign-key property must be assigned another non-null value, or the unrelated object must be deleted.

Одно из предложений в этом сообщении является то, что я должен назначить внешний ключ свойству ненулевое значение, но, как я уже говорил, StoredProcedureReportIDимеет правильное значение на оба StoredProcedureReportParameter объектов.

Другие сообщения, которые я прочитал, имеют дело с циклами Update и связывают их с контекстом. Неужели это то, чем я занимаюсь? Действительно ли EF этот плотный? Я надеюсь на .NET pro, чтобы показать мне свет здесь. Там имеет, чтобы быть более простым способом.

+0

Можете ли вы показать точный код C#? –

ответ

4

Это не так сложно. Существует два основных способа работы с использованием EF: прикрепленные объекты и отдельные элементы.

Давайте предположим, что мы имеем 2 entites:

public class Foo 
{ 
    public int FooId { get; set; } 

    public string Description { get; set; } 

    public ICollection<Bar> Bars { get; set; } 
} 

public class Bar 
{ 
    public int BarId { get; set; } 

    public string Description { get; set; } 
} 

вставив

var foo = new Foo() 
{ 
    FooId = 1, 
    Description = "as", 
    Bars = new List<Bar>() 
    { 
     new Bar 
     { 
      BarId = 1, 
      Description = "as" 
     }, 
     new Bar 
     { 
      BarId = 2, 
      Description = "as" 
     }, 
     new Bar 
     { 
      BarId = 2, 
      Description = "as" 
     } 
    } 
}; 

ctx.Foos.Add(foo); 
ctx.SaveChanges(); 

В приведенном выше примере, EF распознает новые элементы, и вставить все из них.

ОБНОВЛЕНИЕ (присоединенной)

var foo = ctx.Foos.Include("Bars").Where(i => i.FooId == 1).FirstOrDefault(); 
foreach (var bar in foo.Bars) 
{ 
    bar.Description = "changed"; 
} 

ctx.SaveChanges(); 

Здесь мы загрузили Foo и засовы из контекста. Они уже привязаны к контексту. Итак, все, что нам нужно сделать, это изменить значения и вызвать SaveChanges(). Все будет хорошо работать.

ОБНОВЛЕНИЕ (ОТДЕЛЬНЫЙ)

var foo = new Foo 
{ 
    FooId = 1, 
    Description = "changed3", 
    Bars = new List<Bar> 
    { 
     new Bar 
     { 
      BarId = 1, 
      Description = "changed3" 
     }, 
     new Bar 
     { 
      BarId = 2, 
      Description = "changed3" 
     } 
    } 
}; 

ctx.Entry(foo).State = EntityState.Modified; 

foreach (var bar in foo.Bars) 
{ 
    ctx.Entry(bar).State = EntityState.Modified; 
} 

ctx.SaveChanges(); 

Здесь мы работаем с элементами, которые уже существуют в базе данных. Однако они не были загружены из EF (они не привязаны). EF ничего не знает о них. Мы должны приложить все их вручную и сказать EF, что они изменены.

УДАЛЕНИЕ (присоединенной)

var foo = ctx.Foos.Include("Bars").Where(i => i.FooId == 1).FirstOrDefault(); 
var bar = foo.Bars.First(); 
foo.Bars.Remove(bar); 
ctx.SaveChanges(); 

Нагрузка шины от EF и просто удалить их из коллекции.

УДАЛЕНИЕ (ОТДЕЛЬНЫЙ)

var bar = new Bar 
{ 
    BarId = 1 
}; 

ctx.Entry(bar).State = EntityState.Deleted; 
ctx.SaveChanges(); 

Здесь, Бар не был загружен из контекста. Итак, мы должны сказать EF, что он удален.


В вашем случае вы отправляете обновленный объект в контроллер MVC; поэтому, вы должны сказать EF, что изменены StoredProcedureReport и StoredProcedureParameters.

Если все свойства модифицируются вы можете использовать:

ctx.Entry(foo).State = EntityState.Modified; 
//remember to do the same in all children objects 

Он отметит все свойства как измененные. Имейте в виду, что если какое-либо свойство не было установлено на просмотр, оно будет обновляться как пустое значение.

Если не все свойства изменяются, вы должны указать, какие именно свойства. Например:

context.Entry(foo).Property("Description").IsModified = true; 
context.Entry(foo).Property("AnotherProperty").IsModified = true; 

Надеюсь, это поможет!

+2

Таким образом, это * это *, что трудно. Вы не можете сделать это, не перебирая детей и не отмечая их «Модифицировано». Использование EF для веб-приложений кажется просто глупым. – Samo

+0

Вы можете создать метод для выполнения задания цикла. –

+1

Да, я это понимаю. Я просто думаю, что это уродливо, что я должен был сделать это для начала. Вся суть чего-то типа EF заключается в том, что ваши объекты остаются привязанными к контексту, но это противоречит природе веб-запросов, где объекты будут введены в отдельном состоянии. Этот цикл является еще одним запахом, который указывает на несоответствие. – Samo

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