2013-06-12 3 views
5

Так что я довольно далеко от кроличьей дыры, используя конструктор Entity Framework, чтобы сделать EDMX, который служит моделью в проекте MVVM. Я только что столкнулся с проблемой, в которой я уверен, что ICollection<>, который был сгенерирован кодом (см. Ниже, например), действительно должен быть ObservableCollection<> для привязки этой коллекции к DataGrid для того, чтобы быть успешным. I думаю Я получаю некоторые хиты о возможности изменения генерации кода EF, чтобы сделать ObservableCollections, а не ICollections. Кто-нибудь когда-либо пробовал это успешно?Как я могу изменить ICollection объекта Entity Framework как ObservableCollection?

Предположим, что другой вариант будет иметь виртуальную машину, которая содержит выбранный объект Customer, также содержит локальный ObservableCollection<Order>, который создается при выборе объекта Customer ... Я просто беспокоюсь о том, что контекст сохраняет и сохраняет данные в синхронизации ,

типичный код поколения объект с ассоциацией в коллекции дочерних объектов:

public partial class Customer 
{ 
    public Customer() 
    { 
     this.Orders = new HashSet<Order>(); 
    } 

    public int Id { get; set; } 
    public System.DateTime Date { get; set; } 

    public virtual ICollection<Order> Orders { get; set; } 
} 

ответ

4

Ваш data logic и models должны быть отдельно от viewmodel и models. Итак, я думаю, что лучший вариант - это то, о чем вы говорите при создании ObservableCollection. Вы всегда можете синхронизировать с контекстом (я забываю точный синтаксис для синхронизации) при сохранении.

+0

Хммм ... правильно. Кроме того, я думаю, что я, возможно, лаял не то дерево последние несколько часов на этом. У меня длинный контекст EF (из-за привязки MVVM), поэтому я вызывал SaveChanges() в контексте моего деструктора адаптеров данных, чтобы убедиться, что изменения сохранены. Оказывается, вы [не можете этого сделать] (http://stackoverflow.com/questions/7105529/handle-is-not-initialized-error/11695464#11695464). Поэтому мои проблемы с «наблюдаемостью» могли быть красной селедкой. – Bob

4

Класс DbSet, который обычно подвергается действию через ваш DbContext, имеет Local имущество, которое является ObservableCollection<T>. См. the official documentation для получения дополнительной информации

+0

В документации, по-видимому, основное внимание уделяется коду First. Я использую дизайнер EDMX, поэтому, в отличие от примеров, которые я не могу изменить, мои классы моделей используют ObservableCollection. Фактически, я могу, но изменение сущностей в конструкторе будет перезаписывать эти изменения. То есть, если нет ответа на мой первоначальный вопрос об изменении шаблона T4. Спасибо за подсказку * Local *. – Bob

2

Да, я сделал это, и он успешно работает для моего бизнес-приложения. Я изменил файл Model.tt, чтобы иметь виртуальный ObservableCollection<T> вместо ICollection<T> и заменил HashSet<T> на то же самое.

Я также осуществил INotifyPropertyChanged на лиц с последующей реализацией:

public event PropertyChangedEventHandler PropertyChanged; 
protected void NotifyPropertyChanged([CallerMemberName] string propertyName = "") 
{ 
    var handler = PropertyChanged; 
    if (handler != null) 
    { 
     handler(this, new PropertyChangedEventArgs(propertyName)); 
    } 
} 

мне нужно включать три дополнительные используя операторы:

using System.ComponentModel; 
using System.Runtime.CompilerServices; 
using System.Collections.ObjectModel; 

Это функция, которую я изменил в CodeStringGenerator на внедрить мои геттеры и сеттеры: (К сожалению, я до сих пор не пришел к тому, чтобы сделать это более читаемым)

public string Property(EdmProperty edmProperty) 
{ 
    var fourSpaces = " "; 
    return string.Format(
     CultureInfo.InvariantCulture, 
     "{0} {1} _{2};{3}{4}{0} {1} {2}{3}{4}{{{3}{4}{4}{5}get {{ return _{2}; }} {3}{4}{4}{6}set{3}{4}{4}{{{3}{4}{4}{4}if (value == _{2}) return;{3}{4}{4}{4}_{2} = value;{3}{4}{4}{4}NotifyPropertyChanged();{3}{4}{4}}}{3}{4}}}{3}", 
     Accessibility.ForProperty(edmProperty), 
     _typeMapper.GetTypeName(edmProperty.TypeUsage), 
     _code.Escape(edmProperty), 
     Environment.NewLine, 
     fourSpaces, 
     _code.SpaceAfter(Accessibility.ForGetter(edmProperty)), 
     _code.SpaceAfter(Accessibility.ForSetter(edmProperty))); 
} 

И это образец полный сгенерированный файл объект для справки:

namespace Eagl.Eagle.Data 
{ 
    using System; 
    using System.ComponentModel; 
    using System.Runtime.CompilerServices; 
    using System.Collections.Generic; 
    using System.Collections.ObjectModel; 

    public partial class Game : INotifyPropertyChanged 
    { 
     public event PropertyChangedEventHandler PropertyChanged; 
     protected void NotifyPropertyChanged([CallerMemberName] string propertyName = "") 
     { 
      var handler = PropertyChanged; 
      if (handler != null) 
      { 
       handler(this, new PropertyChangedEventArgs(propertyName)); 
      } 
     } 

     public Game() 
     { 
      this.Playtests = new ObservableCollection<Playtest>(); 
     } 

     public int _Id; 
     public int Id 
     { 
      get { return _Id; } 
      set 
      { 
       if (value == _Id) return; 
       _Id = value; 
       NotifyPropertyChanged(); 
      } 
     } 

     public string _Name; 
     public string Name 
     { 
      get { return _Name; } 
      set 
      { 
       if (value == _Name) return; 
       _Name = value; 
       NotifyPropertyChanged(); 
      } 
     } 


     public virtual ObservableCollection<Playtest> Playtests { get; set; } 
    } 
} 
+1

Может быть, я чего-то не хватает. Где вы указываете шаблон, чтобы специально использовать ObservableCollection вместо ICollection ? Вы просто заменили ссылки на ICollection в файле tt, а затем вам пришлось добавить код, указанный выше, чтобы все это работало? – Bob

6

Вот что я сделал, и то, что работает для меня с EF Database первым.

Вот что вам нужно быть сгенерированы:

public partial class Parent 
{ 
    public Parent() 
    { 
     this.Children= new ObservableCollection<Child>(); 
    } 

Так что по умолчанию costructor будет заменен. И ObservableCollection - это ICollection, поэтому вам ничего не нужно менять.

Чтобы сделать это каждый раз, когда вы обновляете модель базы данных, вы должны изменить ее.тт файл со следующими частями:

public string UsingDirectives(bool inHeader, bool includeCollections = true) 
{ 
    return inHeader == string.IsNullOrEmpty(_code.VsNamespaceSuggestion()) 
     ? string.Format(
      CultureInfo.InvariantCulture, 
      "{0}using System;{1}" + 
      "{2}", 
      inHeader ? Environment.NewLine : "", 
      includeCollections ? (Environment.NewLine + "using System.Collections.ObjectModel;" 
       + Environment.NewLine + "using System.Collections.Generic;") : "", 
      inHeader ? "" : Environment.NewLine) 
     : ""; 
} 

и это:

foreach (var navigationProperty in collectionNavigationProperties) 
    { 

    this.<#=code.Escape(navigationProperty)#> = new ObservableCollection<<#=typeMapper.GetTypeName(navigationProperty.ToEndMember.GetEntityType())#>>(); 
    } 
+0

Это должен быть принятый ответ. – dotNET

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