19

顧客、会社、従業員などが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);
    }
}

いくつかの注意事項(これらがEFの「ベストプラクティス」であるかどうかは100%わかりません):

  • アドレスのコレクションは、遅延読み込みを可能にするために仮想的です
  • コレクションのプライベートセッターはコレクションの交換を禁止しています
  • コレクションは、ISet連絡先ごとに重複するアドレスがないことを保証するためのものです
  • 方法を使用AddAddressすると、プライマリであるアドレスが常に最大で1つあることを保証できます。

(可能であれば)メソッドを介してアドレスを追加しないようにし、 ...ContactInfo.Addresses.Add()を強制的に使用したいです。ContactInfo.AddAddress(Address address)

を介してアドレスのセットを公開することを考えてReadOnlyCollectionいますが、これはEntity Framework(v5)で機能しますか?

どうすればいいですか?

4

2 に答える 2

14

エド ヴァン アセルドンクが提案したもう 1 つのオプションは、コレクションから動作を継承するカスタム コレクションを作成することです。

ISet の独自の実装を作成する必要がありますが、原則は同じです。

リストを変更するメソッドを非表示にし、それらを古いものとしてマークすることで、ReadOnlyCollection を効果的に取得できますが、コレクションとしてアンボックスされたときに EF は引き続きそれを変更できます。私のバージョンでは、リストの暗黙的な演算子変換を追加したので、アイテムを追加するときにコレクションをボックス化解除する必要はありません。

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

どこ

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

エンティティコレクションは次のとおりです。

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);
于 2013-02-05T14:52:40.157 に答える
3

1 つの方法は、ICollection プロパティを保護し、ICollection プロパティのリストを返すだけの IEnumerable の新しいプロパティを作成することです。

これの欠点は、この都市に住んでいるすべての連絡先情報を取得するなど、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);
    }
}
于 2012-06-26T12:07:55.030 に答える