2013-06-12 13 views
5

Więc jestem całkiem daleko w króliczej nodze przy użyciu projektanta Entity Framework, aby utworzyć EDMX, który służy jako model w projekcie MVVM. Właśnie natknąłem się na problem, który jest dość pewny, że wygenerowany kod ICollection<> (patrz poniżej) naprawdę musi być ObservableCollection<>, aby powiązać kolekcję z DataGrid w celu odniesienia sukcesu. I think Dostaję pewne hity na temat możliwości modyfikacji generowania kodu EF, aby uzyskać ObservableCollections zamiast ICollections. Ktokolwiek próbował to z powodzeniem?Jak zmienić ICollection Entity Framework jako ObservableCollection?

Przypuszczam, że inną opcją byłoby, gdyby maszyna wirtualna zawierająca wybrany obiekt klienta zawierała także lokalny ObservableCollection<Order>, który zostanie utworzony po wybraniu obiektu klienta. Po prostu martwię się o zapisywanie kontekstu i synchronizację danych. .

typowy kod gen obiekt ze stowarzyszenia do kolekcji obiektów podrzędnych:

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; } 
} 

Odpowiedz

4

Twój data logic i models powinny być oddzielone od swojej viewmodel i models. Tak więc, myślę, że lepszym rozwiązaniem jest to, o czym mówisz, tworząc ObservableCollection. Zawsze możesz zsynchronizować się z kontekstem (zapominam o dokładnej składni do synchronizacji) podczas zapisywania.

+0

Hmmm ... prawo. Myślę też, że przez ostatnie kilka godzin szczekałem złe drzewo. Mam długo działający kontekst EF (ze względu na powiązanie MVVM), dlatego wywołałem SaveChanges() w kontekście w moim destruktorze adapterów danych, aby upewnić się, że zmiany zostały zachowane. Okazuje się, że [nie można tego zrobić] (http://stackoverflow.com/questions/7105529/handle-is-not-initialized-error/11695464#11695464). Tak więc moje obawy związane z obserwowalnością mogły być czerwonym śledziem. – Bob

4

Klasa DbSet że zwykle narażony pośrednictwem DbContext ma Local mienia stanowiącego ObservableCollection<T>. Aby uzyskać więcej informacji, zobacz the official documentation

+0

Dokumentacja wydaje się koncentrować na Code First. Używam projektanta EDMX, więc w przeciwieństwie do przykładów nie mogę po prostu zmienić klas modelu, aby używać ObservableCollection. Właściwie mogę, ale zmiana elementów w projektancie spowoduje nadpisanie tych zmian. To znaczy, jeśli nie ma odpowiedzi na moje pierwotne pytanie o modyfikację szablonu T4. Dziękujemy za wskazówkę * Lokalny *. – Bob

2

Tak, zrobiłem to i działa z powodzeniem dla mojej aplikacji biznesowej. Zmodyfikowałem plik Model.tt tak, aby miał wirtualną ObservableCollection<T> zamiast ICollection<T> i zastąpił ją HashSet<T>.

Ja również realizowany INotifyPropertyChanged na podmioty z następującym realizacji:

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

Musiałem zawierać trzy dodatkowe za pomocą instrukcji:

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

Jest to funkcja, że ​​zmieniła się w CodeStringGenerator do Zaimplementuj moje moduły pobierające i ustawiające: (Niestety, nadal nie otrzymałem tego, aby było bardziej czytelne)

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))); 
} 

A to próbka pełny wygenerowany plik jednostka dla odniesienia:

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

Może czegoś brakuje. Gdzie chcesz powiedzieć szablonowi, aby używał ObservableCollection zamiast ICollection ? Czy po prostu zastąpiłeś odniesienie do ICollection w pliku tt, a następnie musiałeś dodać kod, który podałeś powyżej, żeby wszystko działało? – Bob

6

To, co zrobiłem i co działa na mnie z EF Database pierwszy.

To co trzeba być generowane:

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

Tak, że domyślna costructor zostanie zastąpiony. Element ObservableCollection to element ICollection, więc nie trzeba zmieniać niczego innego.

Aby było to widoczne za każdym razem, gdy aktualizujesz swój model bazy danych, musisz go zmienić.Plik tt z następujących części:

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) 
     : ""; 
} 

a to:

foreach (var navigationProperty in collectionNavigationProperties) 
    { 

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

To powinna być zaakceptowana odpowiedź. – dotNET

Powiązane problemy