簡體   English   中英

實體框架只讀集合

[英]Entity Framework read only collections

考慮一個客戶,公司,員工等具有ContactInfo屬性的域,該屬性又包含一組地址,電話,電子郵件等等......

這是我的縮寫ContactInfo:

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

一些注釋(我不是100%確定這些是EF“最佳實踐”):

  • Address(es)的集合是虛擬的,允許延遲加載
  • 私人二手收集器禁止收集更換
  • 集合是一個ISet以確保每個聯系人沒有重復的地址
  • 使用AddAddress方法我可以確保總是最多1個地址是主要的....

我希望(如果可能的話)阻止通過ContactInfo.Addresses.Add()方法添加地址並強制使用ContactInfo.AddAddress(Address address) ...

我正在考慮通過ReadOnlyCollection公開地址集,但這是否適用於Entity Framework(v5)?

我該怎么做?

Edo van Asseldonk建議的另一個選項是創建一個從Collection繼承其行為的自定義集合。

您必須為ISet制作自己的實現,但原理是相同的。

通過隱藏修改列表並將其標記為過時的任何方法,您可以有效地獲得ReadOnlyCollection,但是當它取消裝箱為Collection時,EF仍然可以修改它。 在我的版本中,我為List添加了一個隱式運算符轉換,因此我們不必在添加項時取消收集集合:

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

哪里

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

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

這樣您仍然可以像往常一樣運行Linq,但在嘗試修改Collection屬性時會得到正確的使用警告。 將它解壓縮到集合將是唯一的方法:

((Collection<MyEntity>)ListProperty).Add(entity);

一種方法是保護ICollection屬性並創建IEnumerable的新屬性,該屬性只返回ICollection屬性的列表。

這樣做的缺點是您無法通過ContactInfo查詢地址,例如獲取位於此城市的所有contactinfo。

這是不可能的!:

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

碼:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM