2013-12-08 4 views
3

Скажем, у меня есть две сущности:Как Entity Framework 5 исполняет создание/обновление, когда есть отношение

public class Menu 
{ 
    //other properties.. 
    public virtual ICollection<SubMenu> SubMenus { get; set; } 
} 

и второй объект:

public class SubMenu 
{ 
    //other properties.. 
    public int MenuID { get; set; } 
    public virtual Menu Menu { get; set; } 
} 

как же EF 5 продолжает отслеживать на отношения между субъектами и что мне нужно передать, чтобы выполнить операции Create/Update?

Существует несколько примеров сценариев, в которых я не уверен, что мне нужно, и что мне не нужно было передавать в качестве значений, чтобы дать EF 5 достаточно информации для выполнения задачи.

Например:

  • Создание меню и подменю одновременно

Допустим, я представил форму с данными для нового Menu содержащего SubMenu, что я хочу сохранить мой база данных. Мой код будет что-то вроде:

Menu menu = new Menu(); 
menu.Name = model.Name; 
menu.Description = model.Description; 
//and so on.. 

затем в подменю я что-то подобное:

SubMenu subMenu = new SubMenu(); 
subMenu.Name = model.sub.Name; 
subMenu.Image = model.sub.Image; 
subMenu.Menu = //The menu does not exist yet... 
subMenu.MenuID = //I don't have Menu so no ID either 

как именно EF 5 работает в этом сценарии? Как следует действовать для создания записей в Menu и SubMenu?

  • Создание субменю для существующего меню

Второй сценарий, который меня смущает, когда я должен создать новую запись, которую я должен относиться к существующим Menu. Опять мой код выглядит примерно так:

SubMenu subMenu = new SubMenu(); 
subMenu.Name = model.sub.Name; 
subMenu.Image = model.sub.Image; 
subMenu.Menu = //hmm? 
subMenu.MenuID = //hmm? 

В этом случае я уже существующий Menu таким образом я могу получить оба - точные Menu объект для этого SubMenu или просто MenuId. Когда я смотрю на subMenu лица, если я прохожу весь Menu объект как:

subMenu.Menu = меню // здесь меню экземпляр Menu

Я могу видеть, что теперь subMenu.Menu держит все свойства объекта, включая MenuId, нужно ли мне его предоставить? subMenu.MenuId = menu.MenuId? Как EF 5 делает отношение и что именно мне нужно предоставить?

ответ

3

Для создания меню и подменю, в то же время, необходимо реализовать нулевой образец объекта (инициализировать SubMenu в CTOR класса меню)

public class Menu 
{ 
    public int Id { set; get; } 
    public string Name { set; get; } 
    public string Description { set; get; } 

    public virtual ICollection<SubMenu> SubMenus { get; set; } 

    public Menu() 
    { 
     SubMenus = new List<SubMenu>(); 
    } 
} 

Затем вы можете добавить подменю с помощью SubMenus.Add метод

using (var context = new MyContext()) 
    { 
     Menu menuItem1 = new Menu(); 
     menuItem1.Name = "modelName"; 
     menuItem1.Description = "modelDescription"; 

     SubMenu subMenu1 = new SubMenu(); 
     subMenu1.Name = "subName1"; 

     menuItem1.SubMenus.Add(subMenu1); // how to define sum-menus (SubMenus is not null anymore) 

     context.Menus.Add(menuItem1); 

     context.SaveChanges(); 
    } 

Теперь EF запускает эти запросы автоматически. Она вставляет корневой элемент, а затем использует его идентификатор для дочерних элементов:

INSERT [dbo].[Menus]([Name], [Description]) 
VALUES (@0, @1) 
SELECT [Id] 
FROM [dbo].[Menus] 
WHERE @@ROWCOUNT > 0 AND [Id] = scope_identity() 
-- @0: 'modelName' (Type = String, Size = -1) 
-- @1: 'modelDescription' (Type = String, Size = -1) 
-- Executing at 2013/12/11 02:27:50 ?.? +03:30 
-- Completed in 43 ms with result: SqlDataReader 

INSERT [dbo].[SubMenus]([Name], [MenuID]) 
VALUES (@0, @1) 
SELECT [Id] 
FROM [dbo].[SubMenus] 
WHERE @@ROWCOUNT > 0 AND [Id] = scope_identity() 
-- @0: 'subName1' (Type = String, Size = -1) 
-- @1: '1' (Type = Int32) 
-- Executing at 2013/12/11 02:27:50 ?.? +03:30 
-- Completed in 26 ms with result: SqlDataReader 

И создать новое вложенное и соотнося его к существующему меню, так же, как и раньше. Использовать existingMenuItem.SubMenus.Add(newSubMenuItem);

using (var context = new MyContext()) 
    { 
     var existingMenuItem = context.Menus.Find(1); 

     SubMenu newSubMenu = new SubMenu(); 
     newSubMenu.Name = "subName2"; 

     existingMenuItem.SubMenus.Add(newSubMenu); // how to define sum-menus 
     context.SaveChanges(); 
    } 
+0

я сделал (я признаю, - быстро) исследования и не смогли найти модель с 'нулевым object' в это имя, не говоря уже о связанных с каким-то' 'EF5' и Code First '. Есть ли другая причина для: 'public Menu() { SubMenus = новый Список (); } 'за тем, как можно использовать расширения для' List', например '.Add()'? – Leron

+0

Публичный/виртуальный - это еще один вопрос ... –

+0

@philsoady Я не прошу о ленивой загрузке и тому подобное, но в чем разница между созданием экземпляра коллекции в самой сущности или после «Меню меню = новое меню(); а затем 'menu.SubMenu = новый список ();'. Я видел пример людей, делающих это в сущности, но я не вижу разницы между созданием экземпляра в коде и его экземпляром в сущности, за исключением, конечно, оптимизация для написания одного и того же кода только один раз. Но я спрашиваю, есть ли другие причины этого очевидного. – Leron

1

Ответ на VahidN будет работать. Но я не уверен, что он полностью затронул вопрос.

EF Может выполнить некоторую проверку перед отправкой команд в базу данных. Поскольку она имеет модель ... Вы можете посмотреть на модель слишком

ObjectContext objContext = ((IObjectContextAdapter)context).ObjectContext; 
MetadataWorkspace workspace = objContext.MetadataWorkspace; 
IEnumerable<EntityType> managedTypes = workspace.GetItems<EntityType>(DataSpace.OSpace); 

Есть некоторые реляционные ограничения, что DB возвращается на saveChanges
Это стоит посмотреть на Context.GetValidationErrors()

Вы можете добавить главный Poco записи, зафиксировать их (через saveCnages), а затем добавить элементы SubPoco и сохранить их.
BUT ваш вопрос, кажется, спрашивает: что, если я добавлю в то же время ...

Вы также можете добавить как Main, так и Sub вместе без использования свойства NAV на MAIN poco.

Рассмотрим

 var myMAINpoco = new MyMainPoco() 
     { // Id is set by DB 
      Content = "Test", 
     }; 

     repMain.Add(mypoco); // add to context 

     var mySubPoco2 = new MySubPoco() 
     { 
      //My id is determined by DB 
      // MainId = // I dont know this yet, but thats OK, since I have the nav property set. 
      // Ef will update MAINID afterwards for me. 
      Content = "TEST content for SUBRECORD ", 
      ParentPoco = mypoco // THE NAV property of the New MAINPOCO 
           // that will be commited with me 
     }; 

     repSub.Add(mySubPoco2); 

     //subpoco.mainid = 0 
     uow.Commit(); 
     //subpoco.mainid = n and refers the NEW id Just allocated to MainPoco.Id 
Смежные вопросы