How to load entities into private collections using the entity framework

I have a POCO domain model which is wired up to the entity framework using the new ObjectContext class.

public class Product
    {
        private ICollection<Photo> _photos;

        public Product()
        {
            _photos = new Collection<Photo>();         
        }

        public int Id { get; set; }
        public string Name { get; set; }
        public virtual IEnumerable<Photo> Photos
        {
            get
            {
                return _photos;
            }
        }

        public void AddPhoto(Photo photo)
        {
            //Some biz logic
            //...
            _photos.Add(photo);
        }
    }

In the above example i have set the Photos collection type to IEnumerable as this will make it read only. The only way to add/remove photos is through the public methods.

The problem with this is that the Entity Framework cannot load the Photo entities into the IEnumerable collection as it's not of type ICollection.

By changing the type to ICollection will allow callers to call the Add mentod on the collection itself which is not good.

What are my options?

Edit:

I could refactor the code so it does not expose a public property for Photos:

public class Product
    {
    public Product()
    {
        Photos = new Collection<Photo>();         
    }

    public int Id { get; set; }
    public string Name { get; set; }
    private Collection<Photo> Photos {get; set; }

    public IEnumerable<Photo> GetPhotos()
    {
        return Photos; 
    }

    public void AddPhoto(Photo photo)
    {
        //Some biz logic
        //...
        Photos.Add(photo);
    }

    }

And use the GetPhotos() to return the collection. The other problem with the approach is that I will loose the change tracking abilities as I cannot mark the collection as Virtual - It is not possible to mark a property as private virtual.

In NHibernate I believe it's possible to map the proxy class to the private collection via configuration. I hope that this will become a feature of EF4. Currently i don't like the inability to have any control over the collection!


这样做的方法是在模型中映射一个受保护的虚拟属性,并返回一个IEnumerable返回的公共属性。

public class Product
{
    public Product()
    {
        PhotoCollection = new Collcation<Photo>();
    }

    public int Id { get; set; }
    public string Name { get; set; }
    protected virtual ICollection<Photo> PhotoCollection {get; set; }

    public IEnumerable<Photo> Photos
    {
        get { return PhotoCollection ; } 
    }

    public void AddPhoto(Photo photo)
    {
        //Some biz logic
        //...
        PhotoCollection .Add(photo);
    }
}

Anton, it would help me understand your problem more if you can explain why is it that you do not want developers to access the Add method of your collection. Is this because the list is strictly read-only, or is it because you want to run some custom business logic when a new entity is added?

Anyway... I am going to assume that you are trying to do the latter (ie run custom business logic when the collection is modified). I have done a similar solution on a project of mine, and the idea is as follows:

The TT template that produces POCOs in EF4 creates all collections as TrackableCollection lists. This class has an event called 'CollectionChanged' which you can subscribe to and listen to any changes to your collection.

So you can do something as follows:

public class Product
{
    public Product()
    {
        Photos.CollectionChanged += ListCollectionChanged;
    }

    public int Id { get; set; }

    public string Name { get; set; }

    public TrackableCollection<Photo> Photos
    {
        get
        {
            // default code generated by EF4 TT
        }
        set
        {
            // default code generated by EF4 TT
        }
    }

    private void ListCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        switch (e.Action)
        {
            // A new item has been added to collection
            case NotifyCollectionChangedAction.Add:
                {
                    T newItem = (T) e.NewItems[0];
                    // Run custom business logic
                }
                break;

            // An existing item has been removed
            case NotifyCollectionChangedAction.Remove:
                {
                    T oldItem = (T) e.OldItems[0];
                    // Run custom business logic
                }
                break;
        }
    }
}

The nice thing about the above solution is that you still use your Product entity in an 'EF' manner... were any developer in your team can simply access a property of the entity directory and need run an explicit hard typed function.


Bit late to the party but this is what Observable objects are for. Allow the data structure to do what it does best. Use ObservableCollection as your field type if you don't want to build your own collection that does what you need and expose the regular ICollection type from your property. You can run any logic in the parent entity you need when the related entities in the collection change via the CollectionChanged event. If you need to selectively enable or disable modifications it's easy enough to extend an existing collection type or write a proxy collection that allows a call to a method to toggle the mutability of the collection (ISupportInitialize can be used to good effect for representing this ability BTW).

链接地址: http://www.djcxy.com/p/45302.html

上一篇: 是否有同步SQL Server表的标准做法?

下一篇: 如何使用实体框架将实体加载到私有集合中