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

我有一个使用新的ObjectContext类连接到实体框架的POCO域模型。

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

在上面的例子中,我已经将Photos集合类型设置为IEnumerable,因为这将使其成为只读。 添加/删除照片的唯一方法是通过公共方法。

问题在于实体框架无法将Photo实体加载到IEnumerable集合中,因为它不是ICollection类型。

通过将类型更改为ICollection,将允许调用者调用集合本身的Add mentod,这是不好的。

我有什么选择?

编辑:

我可以重构代码,以便它不公开照片的公共属性:

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

    }

并使用GetPhotos()返回集合。 该方法的另一个问题是,我将失去更改跟踪功能,因为我无法将该集合标记为虚拟 - 无法将属性标记为私有虚拟。

在NHibernate中,我相信可以通过配置将代理类映射到私有集合。 我希望这将成为EF4的一个特色。 目前我不喜欢无法控制集合!


这样做的方法是在模型中映射一个受保护的虚拟属性,并返回一个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,如果你能解释为什么你不希望开发者访问你的集合的Add方法,它会帮助我更好地理解你的问题。 这是因为列表是严格只读的,还是因为您想在添加新实体时运行一些自定义业务逻辑?

无论如何...我会假设你正在尝试做后者(即在收集被修改时运行自定义业务逻辑)。 我在一个项目上做了类似的解决方案,其想法如下:

在EF4中生成POCO的TT模板将所有集合创建为TrackableCollection列表。 这个类有一个名为'CollectionChanged'的事件,您可以订阅并收听对您收藏集的任何更改。

所以你可以做如下的事情:

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

关于上述解决方案的好处是,您仍然以'EF'的方式使用您的Product实体...您团队中的任何开发人员都可以简单地访问实体目录的属性,并且需要运行明确的硬键入功能。


晚了会派对,但这是Observable对象的用途。 让数据结构尽其所能。 如果您不想构建自己的集合,并根据需要显示常规ICollection类型,请使用ObservableCollection作为字段类型。 当集合中的相关实体通过CollectionChanged事件更改时,您可以在需要的父实体中运行任何逻辑。 如果您需要选择性地启用或禁用修改,则很容易扩展现有集合类型或编写代理集合,以允许调用方法来切换集合的可变性(ISupportInitialize可用于表示此功能的良好效果)BTW )。

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

上一篇: How to load entities into private collections using the entity framework

下一篇: Control VLC from Python in Windows