多态去除对象添加到对象集&所述; TEntity>会不会提高IBindingList.ListChanged的对象集< TEntity> .IListSource.GetList() [英] Polymorphic removal of objects added to ObjectSet<TEntity> will NOT raise the IBindingList.ListChanged on ObjectSet<TEntity>.IListSource.GetList()

查看:153
本文介绍了多态去除对象添加到对象集&所述; TEntity>会不会提高IBindingList.ListChanged的对象集< TEntity> .IListSource.GetList()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

概述/说明

简单:从 TEntity 多态性去除运行时类型的来源的对象添加到对象集&LT; TEntity&GT; 不会提高通过的<$返回的 IBindingList的对象的 IBindingList.ListChanged 事件C $ C>对象集&LT; TEntity&GT; .IListSource.GetList()方法

不过,除去实例的运行时类型的匹配 TEntity 的ListChanged 事件。

要澄清,在任何时候,对象是有效地从底层集合或数据视图/存储,但是当这些对象是严格从实际派生类型的实例 TEntity 使用时,的ListChanged 事件不会引发通知其清除。

这仅仅是一个惊人的BUG进行适当的数据绑定支持运行时多态性对集合的目的。

复制

模型设置

  1. 在表每个类型的策略。
  2. 在映射和验证对gemerated SQL数据库Server 2012的防爆preSS。实体模型

这是实体体系结构(伪UML):

  FiascoEntityContext:ObjectContext的
  + FOOS:对象集&LT;富&GT;

富:EntityObject
  +编号:的Int32
  +产品名称:字符串

SpecialFoo:富
  + SpecialProperty:字符串
 

示范code

 使用系统;
使用System.Collections.Generic;
使用System.Linq的;
使用System.Text;
使用System.ComponentModel;
使用System.Data.Objects;

命名空间FiascoEF {
    类节目{
        静态无效的主要(字串[] args){
            使用(FiascoEntityContext上下文=新FiascoEntityContext()){
                //
                //添加一些FOOS
                //
                context.Foos.AddObject(新富{NAME =Foo1});
                context.Foos.AddObject(新BetterFoo {名称=BetterFoo1,SpecialProperty =特别的东西});
                context.SaveChanges();
                //
                //显示的内容
                //
                Console.WriteLine(列出所有FOOS:);
                的foreach(在context.Foos VAR富){
                    Console.WriteLine(得到了{0}:ID = {1}名称= {2}(州= {3}),FOO,foo.Id,foo.Name,foo.EntityState);
                }
                //
                //附加处理程序IBindingList的的ListChanged事件通过c​​ontext.Foos为IListSource返回
                //注意:要在这里做bacause的SaveChanges()以上将复位内部IBindingList的
                //
                VAR的BindingList =(context.Foos为IListSource).GetList()为IBindingList的;
                bindingList.ListChanged + =新ListChangedEventHandler(bindingList_ListChanged);
                //
                //删除所有FOOS,并显示状态。期望事件处理上述被调用。
                //
                Console.WriteLine(删除所有FOOS:);
                的foreach(在context.Foos VAR富){
                    context.Foos.DeleteObject(富);
                    Console.WriteLine(已删除{0}:ID = {1}名称= {2}(州= {3}),FOO,foo.Id,foo.Name,foo.EntityState);
                }
                context.SaveChanges();
            }
        }

        静态无效bindingList_ListChanged(对象发件人,ListChangedEventArgs E){
            Console.WriteLine(关于{0}事件:{1},发件人,e.ListChangedType);
        }
    }
}
 

预期结果

 列出所有FOOS:
     得到FiascoEF.Foo:ID = 257名称= Foo1(州=不变)
     得到FiascoEF.BetterFoo:ID = 258名称= BetterFoo1(州=不变)
删除所有FOOS:
     事件在System.Data.Objects.ObjectView`1 [FiascoEF.Foo]:ItemDeleted
     删除FiascoEF.Foo:ID = 257名称= Foo1(州=删除)
     事件在System.Data.Objects.ObjectView`1 [FiascoEF.Foo]:ItemDeleted
     删除FiascoEF.BetterFoo:ID = 258名称= BetterFoo1(州=删除)
 

实际结果

 列出所有FOOS:
     得到FiascoEF.Foo:ID = 257名称= Foo1(州=不变)
     得到FiascoEF.BetterFoo:ID = 258名称= BetterFoo1(州=不变)
删除所有FOOS:
     事件在System.Data.Objects.ObjectView`1 [FiascoEF.Foo]:ItemDeleted
     删除FiascoEF.Foo:ID = 257名称= Foo1(州=删除)
     删除FiascoEF.BetterFoo:ID = 258名称= BetterFoo1(州=删除)
 

研究

通过反射发现实际 IBindingList的返回类型为的ObjectView&LT; TElement&GT; ,而这种类型的代表去除操作内部 IObjectViewData&LT; TElement&GT; 。发现该接口的实现是 ObjectViewQueryResultData&LT; TElement&GT; 定义:

 公共ListChangedEventArgs OnCollectionChanged(对象发件人,CollectionChangeEventArgs即ObjectViewListener监听器){

    ListChangedEventArgs changeArgs = NULL;

    如果(e.Element.GetType()IsAssignableFrom(typeof运算(TElement))及。&安培; _bindingList.Contains((TElement)(e.Element))){
        ...
        changeArgs =新ListChangedEventArgs(ListChangedType.ItemDeleted,...);
        ...
    }

    返回changeArgs;
}
 

校验:

 如果(e.Element.GetType()IsAssignableFrom(typeof运算(TElement))及。&安培; ...){...}
 

好像假的......也许下面的用意?

 如果(typeof运算(TElement).IsAssignableFrom(e.Element.GetType())及和放大器; ...){...}
 

解决方案

很公平,错误报告给微软 - 的 http://connect.microsoft.com/VisualStudio/feedback/details/749368 ......他们似乎已经承认了问题,但目前还不清楚他们会做些什么。

记住,我们正在谈论的对象集&LT检索到的 IBindingList的实施; T&GT; 作为观察 IListSource 有关数据绑定,因此预计该事件被解雇,只是因为它为均匀名单的情况,目的

我挣脱通过定义一个类继承自的ObservableCollection&LT; T&GT; 并包装对象集&LT; T&GT; ,然后实现 IListSource DbExtensions.ToBindingList&LT的帮助; T&GT;(此的ObservableCollection&LT; T&GT;)扩展方法

另外,我能继续前进,并开始使用的DbContext API完全,但确定自己的的ObservableCollection&LT; T&GT; 让我能够继续使用的ObjectContext 就目前而言,这正是我想要的。

OVERVIEW/DESCRIPTION

Simple: Polymorphic removal of objects of runtime types derived from TEntity added to an ObjectSet<TEntity> will NOT raise the IBindingList.ListChanged event on the IBindingList object returned by the of the ObjectSet<TEntity>.IListSource.GetList() method.

However, removal of instances whose runtime type match TEntity are effectively notified on the ListChanged event.

To clarify, at all times, objects are effectively removed from the underlying collections or data views/stores, but when these objects are instances of types strictly derived from the actual TEntity used, the ListChanged event is not raised to notify of their removal.

This is simply a phenomenal BUG for the purposes of appropriate data-binding support of runtime polymorphism for collections.

REPLICATION

Model Setup

  1. Table per Type Strategy.
  2. Entity model mapped and validated against gemerated SQL database on Server 2012 Express.

This is the entity hierarchy (pseudo-UML):

FiascoEntityContext : ObjectContext
  + Foos : ObjectSet<Foo>

Foo : EntityObject
  + Id: Int32
  + Name: String

SpecialFoo : Foo
  + SpecialProperty: String

Demonstration Code

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, foo.Id, foo.Name, foo.EntityState);
                }
                context.SaveChanges();
            }
        }

        static void bindingList_ListChanged(object sender, ListChangedEventArgs e) {
            Console.WriteLine("     Event on {0}: {1}", sender, e.ListChangedType);
        }
    }
}

Expected Results

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)

Actual Results

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)

RESEARCH

Through reflector found that the actual IBindingList returned is of type ObjectView<TElement>, and this type delegates removal operations to an internal IObjectViewData<TElement>. The implementation found for that interface is ObjectViewQueryResultData<TElement> which defines:

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

The check:

if (e.Element.GetType().IsAssignableFrom(typeof(TElement)) && ...) { ... }

seems bogus... probably the following was intended?

if (typeof(TElement).IsAssignableFrom(e.Element.GetType()) && ...) { ... }

解决方案

Fair enough, bug reported to Microsoft — http://connect.microsoft.com/VisualStudio/feedback/details/749368... They seem to have acknowledged the issue, but it's not clear what they will do.

Remember, we're talking about the IBindingList implementation retrieved by the ObjectSet<T> when viewed as a IListSource for the purposes of data-binding, so the event is expected to be fired, just as it does for the case of a homogeneous list.

I broke loose by defining a class that inherits from ObservableCollection<T> and wraps the ObjectSet<T>, then implement IListSource with the help of the DbExtensions.ToBindingList<T>(this ObservableCollection<T>) extension method.

Alternatively, I could just move on and start using the DbContext API entirely, but defining my own ObservableCollection<T> allows me to keep using ObjectContext for now, which is what I want.

这篇关于多态去除对象添加到对象集&所述; TEntity&GT;会不会提高IBindingList.ListChanged的对象集&LT; TEntity&GT; .IListSource.GetList()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆