2012-06-25 13 views
18

Betrachten Sie eine Domäne, in der ein Kunde, ein Unternehmen, ein Mitarbeiter usw. eine ContactInfo-Eigenschaft hat, die ihrerseits eine Reihe von Adressen, Telefonnummern, E-Mail (s) usw. enthält usw ...Entity Framework Nur-Lese-Sammlungen

Hier ist meine abgekürzt Contact:

public class ContactInfo : Entity<int> 
{ 
    public ContactInfo() 
    { 
     Addresses = new HashSet<Address>();   
    } 

    public virtual ISet<Address> Addresses { get ; private set; } 

    public Address PrimaryAddress 
    { 
     get { return Addresses.FirstOrDefault(a => a.IsPrimary); } 
    } 

    public bool AddAddress(Address address) 
    { 
     // insure there is only one primary address in collection 
     if (address.IsPrimary) 
     {     
      if (PrimaryAddress != null) 
      { 
       PrimaryAddress.IsPrimary = false; 
      } 
     } 
     else 
     { 
      // make sure the only address in collection is primary 
      if (!Addresses.Any()) 
      { 
       address.IsPrimary = true; 
      } 
     } 
     return Addresses.Add(address); 
    } 
} 

Einige Anmerkungen (ich bin nicht 100% sicher, ob diese EF "best practices") sind:

  • Sammlung von Adress (es) ist virtuell, um laues Laden zu ermöglichen
  • private Setter auf Sammlung verbietet Sammlung Ersatz
  • Sammlung ein ISet, um sicherzustellen, dass es keine doppelten Adressen pro Kontakt
  • mit AddAddress Methode, die ich versichern kann, dass es immer und höchstens 1-Adresse ist die primäre ist ...
  • .

ich würde (wenn möglich) wie Adressen über ContactInfo.Addresses.Add() Verfahren zu verhindern, das Hinzufügen und von ContactInfo.AddAddress(Address address) mit zu zwingen ...

ich denke die eingestellte Belichtungs von Adressen über ReadOnlyCollection, aber wird dies mit Entity Framework (v5) funktionieren?

Wie würde ich darüber gehen?

Antwort

3

Eine Möglichkeit besteht darin, die ICollection-Eigenschaft zu schützen und eine neue Eigenschaft von IEnumerable zu erstellen, die nur die Liste der ICollection-Eigenschaft zurückgibt.

Der Nachteil ist, dass Sie nicht in der Lage sind, Adressen über die ContactInfo wie alle Kontaktinfo, die in dieser Stadt lebt abfragen.

Dies ist nicht möglich !:

from c in ContactInfos 
where c.Addresses.Contains(x => x.City == "New York") 
select c 

Code:

public class ContactInfo : Entity<int> 
{ 
    public ContactInfo() 
    { 
     Addresses = new HashSet<Address>();   
    } 

    protected virtual ISet<Address> AddressesCollection { get ; private set; } 

    public IEnumerable<Address> Addresses { get { return AddressesCollection; }} 

    public Address PrimaryAddress 
    { 
     get { return Addresses.FirstOrDefault(a => a.IsPrimary); } 
    } 

    public bool AddAddress(Address address) 
    { 
     // insure there is only one primary address in collection 
     if (address.IsPrimary) 
     {     
      if (PrimaryAddress != null) 
      { 
       PrimaryAddress.IsPrimary = false; 
      } 
     } 
     else 
     { 
      // make sure the only address in collection is primary 
      if (!Addresses.Any()) 
      { 
       address.IsPrimary = true; 
      } 
     } 
     return Addresses.Add(address); 
    } 
} 
+0

Sollte es nicht möglich sein, das IEnumerable an ein ISet zu übertragen und all die Magie zu tun, die danach versteckt werden sollte? –

+0

@Michael Leider ist dies keine Option für mich ... Ich muss in der Lage sein, abzufragen ... – zam6ak

+1

Es funktioniert nicht zuerst in Code. EF erstellt keine Tabelle für die geschützte Sammlung/den geschützten Satz. – 101V

14

Eine weitere Option vorgeschlagen von Edo van Asseldonk ist eine benutzerdefinierte Sammlung zu erstellen, die das Verhalten von Sammlung erbt.

Sie müssten Ihre eigene Implementierung für ISet machen, aber das Prinzip ist das gleiche.

Durch das Ausblenden aller Methoden, die die Liste ändern und sie als veraltet markieren, erhalten Sie effektiv eine ReadOnlyCollection, aber EF kann sie immer noch ändern, wenn sie als Collection entpackt ist.In meiner Version Ich habe eine implizite Operator-Konvertierung für Liste hinzugefügt, so dass wir die Sammlung unbox müssen, wenn das Hinzufügen von Elementen nicht:

var list = ListProperty.ToList(); 
list.Add(entity) 
ListProperty = list; 

Wo

public virtual EntityCollection<MyEntity> ListProperty { get; protected set; } 

und hier ist die EntityCollection:

public class EntityCollection<T> : Collection<T> 
{ 
    [Obsolete("Unboxing this collection is only allowed in the declarating class.", true)] 
    public new void Add(T item) { } 

    [Obsolete("Unboxing this collection is only allowed in the declarating class.", true)] 
    public new void Clear() { } 

    [Obsolete("Unboxing this collection is only allowed in the declarating class.", true)] 
    public new void Insert(int index, T item) { } 

    [Obsolete("Unboxing this collection is only allowed in the declarating class.", true)] 
    public new void Remove(T item) { } 

    [Obsolete("Unboxing this collection is only allowed in the declarating class.", true)] 
    public new void RemoveAt(int index) { } 

    public static implicit operator EntityCollection<T>(List<T> source) 
    { 
     var target = new EntityCollection<T>(); 
     foreach (var item in source) 
      ((Collection<T>) target).Add(item); // unbox 

     return target; 
    } 
} 

Auf diese Weise können Sie Linq weiterhin wie gewohnt ausführen, erhalten jedoch eine ordnungsgemäße Warnung, wenn Sie versuchen, die Collection-Eigenschaft zu ändern. Es wäre die einzige Möglichkeit, es in eine Collection zu verpacken: