如何使用实体框架将实体加载到私有集合中
我有一个使用新的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