实体框架只读集合实体框架只读集合(Entity Framework read only collec

2019-06-12 06:23发布

考虑一个域名,其中一个客户,公司,员工,等等等等,有一个的ContactInfo属性又包含了一组地址(ES)的,电话(ES),电子邮件(S),等等,等等...

这里是我的缩写的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“最佳实践”):

  • 地址(ES)的集合是虚拟的允许延迟加载
  • 在收集私人二传手禁止收集更换
  • 回收是一个ISet ,以确保有每个接触没有重复的地址
  • 使用AddAddress方法我可以保证始终有和至多1个地址是主....

我想(如果可能的话),以防止添加地址通过ContactInfo.Addresses.Add()方法和使用的强制ContactInfo.AddAddress(Address address) ...

我想通过揭露组地址ReadOnlyCollection而是与实体框架(V5)这项工作?

我将如何去吗?

Answer 1:

一种方法是使保护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);
    }
}


Answer 2:

江户面包车Asseldonk建议另一种方法是创建一个自定义集合继承Collection中的行为。

你必须使自己的ISet用于执行,但原理是一样的。

通过隐藏修改列表中的任何方法,以及将它们标记为已过时您有效地得到一个ReadOnlyCollection但EF仍然可以当它是作为拆箱收集对其进行修改。 在我的版本我已经添加了列表的隐式转换操作,所以我们没有加入项目时拆箱集合:

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<MyEntity>)ListProperty).Add(entity);


文章来源: Entity Framework read only collections