c# – 添加到ObjectSet的对象的多态删除不会引发ObjectSet.IList
概览/描述
简单:从TEntity派生的运行时类型的对象的多态删除添加到ObjectSet< TEntity>不会在ObjectSet< TEntity> .IListSource.GetList()方法返回的IBindingList对象上引发IBindingList.ListChanged事件. 但是,在ListChanged事件上有效地通知删除运行时类型与TEntity匹配的实例. 为了澄清,在任何时候,对象都被有效地从底层集合或数据视图/存储中移除,但是当这些对象是严格从所使用的实际TEntity派生的类型的实例时,不会引发ListChanged事件以通知它们的移除. 对于集合的运行时多态性的适当数据绑定支持,这只是一个惊人的BUG. REPLICATION 型号设置 >每种类型策略表. 这是实体层次结构(伪UML): FiascoEntityContext : ObjectContext + Foos : ObjectSet<Foo> Foo : EntityObject + Id: Int32 + Name: String SpecialFoo : Foo + SpecialProperty: String 示范代码 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ComponentModel; using System.Data.Objects; namespace FiascoEF { class Program { static void Main(string[] args) { using (FiascoEntityContext context = new FiascoEntityContext()) { // // add some foos // context.Foos.AddObject(new Foo { Name = "Foo1" }); context.Foos.AddObject(new BetterFoo { Name = "BetterFoo1",SpecialProperty = "Something Special" }); context.SaveChanges(); // // show the contents // Console.WriteLine("Listing all foos:"); foreach (var foo in context.Foos) { Console.WriteLine(" Got {0}: Id={1} Name={2} (State={3})",foo,foo.Id,foo.Name,foo.EntityState); } // // attach handler for the ListChanged event of the IBindingList returned by context.Foos as IListSource // NOTE: have to do this here bacause SaveChanges() above will reset the internal IBindingList // var bindingList = (context.Foos as IListSource).GetList() as IBindingList; bindingList.ListChanged += new ListChangedEventHandler(bindingList_ListChanged); // // delete all foos and show state. expect the event handler above to be invoked. // Console.WriteLine("Deleting all foos:"); foreach (var foo in context.Foos) { context.Foos.DeleteObject(foo); Console.WriteLine(" Deleted {0}: Id={1} Name={2} (State={3})",foo.EntityState); } context.SaveChanges(); } } static void bindingList_ListChanged(object sender,ListChangedEventArgs e) { Console.WriteLine(" Event on {0}: {1}",sender,e.ListChangedType); } } } 预期成绩 Listing all foos: Got FiascoEF.Foo: Id=257 Name=Foo1 (State=Unchanged) Got FiascoEF.BetterFoo: Id=258 Name=BetterFoo1 (State=Unchanged) Deleting all foos: Event on System.Data.Objects.ObjectView`1[FiascoEF.Foo]: ItemDeleted Deleted FiascoEF.Foo: Id=257 Name=Foo1 (State=Deleted) Event on System.Data.Objects.ObjectView`1[FiascoEF.Foo]: ItemDeleted Deleted FiascoEF.BetterFoo: Id=258 Name=BetterFoo1 (State=Deleted) 实际结果 Listing all foos: Got FiascoEF.Foo: Id=257 Name=Foo1 (State=Unchanged) Got FiascoEF.BetterFoo: Id=258 Name=BetterFoo1 (State=Unchanged) Deleting all foos: Event on System.Data.Objects.ObjectView`1[FiascoEF.Foo]: ItemDeleted Deleted FiascoEF.Foo: Id=257 Name=Foo1 (State=Deleted) Deleted FiascoEF.BetterFoo: Id=258 Name=BetterFoo1 (State=Deleted) 研究 通过反射器发现返回的实际IBindingList是ObjectView< TElement>类型,并且此类型将删除操作委托给内部IObjectViewData< TElement>.为该接口找到的实现是ObjectViewQueryResultData< TElement>它定义: public ListChangedEventArgs OnCollectionChanged(object sender,CollectionChangeEventArgs e,ObjectViewListener listener) { ListChangedEventArgs changeArgs = null; if (e.Element.GetType().IsAssignableFrom(typeof(TElement)) && _bindingList.Contains((TElement) (e.Element))) { ... changeArgs = new ListChangedEventArgs(ListChangedType.ItemDeleted,...); ... } return changeArgs; } 支票: if (e.Element.GetType().IsAssignableFrom(typeof(TElement)) && ...) { ... } 似乎是假的…可能以下是有意的吗? if (typeof(TElement).IsAssignableFrom(e.Element.GetType()) && ...) { ... } 解决方法
很公平,bug报告给微软 –
http://connect.microsoft.com/VisualStudio/feedback/details/749368 ……他们似乎已经承认了这个问题,但目前还不清楚他们会做什么.
记住,我们正在谈论由ObjectSet< T>检索的IBindingList实现.当出于数据绑定的目的被视为IListSource时,预期事件将被触发,就像它对同类列表的情况一样. 我通过定义一个继承自ObservableCollection< T>的类来解决这个问题.并且包装ObjectSet< T>,然后在DbExtensions.ToBindingList< T>(此ObservableCollection< T>)扩展方法的帮助下实现IListSource. 或者,我可以继续完全开始使用DbContext API,但是定义我自己的ObservableCollection< T>允许我现在继续使用ObjectContext,这就是我想要的. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |