2009-04-20 17 views
9

Perdóname si esto se ha preguntado antes; Hice una búsqueda, pero no pude encontrar nada que respondiera específicamente esta pregunta, pero estaría encantado de ser referido.¿La encuadernación de datos de Entity Framework/LINQ to SQL utiliza la reflexión?

Echo un vistazo a Entity Framework y LINQ to SQL, y si bien me gustan los sistemas (y por supuesto la integración LINQ) soy un poco escéptico con respecto al aspecto vinculante de datos. He tomado los resultados de las consultas y los he inspeccionado, y no parecen implementar las interfaces de enlace de listas .NET estándar (IBindingList, y más importante aún, ITypedList), lo que me lleva a creer que los vincula a una grilla (o cualquier otra cosa) va a usar la reflexión para obtener/establecer las propiedades de mi entidad. Esto parece una operación comparativamente costosa, especialmente cuando todo el código se genera de todos modos y podría implementar las interfaces.

¿Alguien tiene alguna idea de esto? ¿Se usa la reflexión para obtener/establecer el valor de las propiedades? En caso afirmativo, ¿tiene esto un impacto en el rendimiento que sea notable, y alguien tiene alguna idea de por qué tomaron esta ruta?

Editar

De hecho, me estoy concentrando en si es o no ITypedList se implementa algún lugar del camino, ya que eso es lo que tiene la capacidad de proporcionar un mecanismo explícito para la definición e interactuar con propiedades sin tener que recurrir a la reflexión. Si bien no tenía un proyecto de LINQ to SQL, inspeccioné un resultado simple de consulta de entidad de Entity Framework y no pareció implementar ITypedList. ¿Alguien sabe si estoy mirando algo incorrectamente o, si no, por qué es este el caso?

Editar 2

Después de aceptar la respuesta de Marc, pensé que podría ser útil para otras personas si he publicado un código simple que utiliza para implementar sin problemas su solución. Pongo el siguiente en el constructor estático para mi clase:

public static ContextName() 
{ 
    foreach(Type type in System.Reflection.Assembly.GetExecutingAssembly() 
     .GetTypes()) 
    { 
     if (type.GetCustomAttributes(typeof(System.Data.Linq.Mapping 
      .TableAttribute), true) != null) 
     { 
      System.ComponentModel.TypeDescriptor.AddProvider(
       new Hyper.ComponentModel.HyperTypeDescriptionProvider(
        System.ComponentModel.TypeDescriptor.GetProvider(
         type)), 
       type); 
     } 
    } 
} 

Si bien esto es para LINQ a SQL, estoy seguro de una versión equivalente se podría escribir para el marco de la entidad. Esto escaneará el ensamblaje de cualquier tipo con el atributo Table y agregará un proveedor personalizado para cada uno de ellos.

Respuesta

3

La API de expresión que sustenta LINQ, etc se basa en la reflexión (MemberInfo), el componente no-modelo (PropertyDescriptor etc) - así que no hay una enorme necesidad de ITypedList. En su lugar, el contenido se infiere a partir de la T en IQueryable<T>, IEnumerable<T> y IList<T> etc.

Lo más cerca que podría obtener es IListSource, pero que seguirán siendo simplemente un envoltorio poco profundas alrededor de una lista escrita a máquina adecuada.

Si el rendimiento del tiempo de ejecución de unión (a PropertyDescriptor) es clave, es posible que desee ver en HyperDescriptor - que utiliza Reflection.Emit y TypeDescriptionProvider para envolver el componente de modelo.

Re el "por qué", etc .; tenga en cuenta que en casi todos los casos con LINQ-to-SQL y EF el Expression (o la parte "crear y establecer miembros") se compilará a un delegado antes de que se invoque, por lo que en el tiempo de ejecución no hay un gran costo de reflexión. Y del mismo modo, con LINQ-to-Objects todo es ya compilado (por el compilador C#).

+0

Marc, si su proyecto HyperDescriptor funciona como lo espero, eso proporcionará exactamente lo que necesito. Todavía me resulta un poco confuso el hecho de que Microsoft no haga uso de su propia infraestructura de enlace de datos y confíe en el TypeDescriptor predeterminado que devuelve ReflectPropertyDescriptors, pero bueno. Si esto funciona, no me importa mucho. –

0

Mirando lo que MSDN tiene que decir en el enlace de datos LINQ a SQL, parece que usa IListSource o IBindingList.

Por cierto, LINQ usa Expression Trees, y eso no refleja tanto como la meta-programación. El rendimiento debería ser mucho mejor que la reflexión. Charlie Calvert cubre esto un poco en este article.

+0

Derecho, soy consciente de que implementa IListSource (y, en el resultado, IBindingList). La interfaz más importante aquí es en realidad ITypedList, ya que es lo que proporciona la lista de objetos PropertyDescriptor para cada propiedad. Sin una implementación explícita de ITypedList (a menos que me falta algo), o el BindingList o el componente BindingSource tiene que volver a PropertyDescriptors basados ​​en la reflexión, que será más lento que si fueran explícitos. –

+0

Además, a menos que tenga algo mal, los árboles de expresiones tienen más que ver con consultar los datos que con la recuperación de datos consultados para operaciones de enlace de datos. –

+0

Sí, los árboles son más para las consultas. Solo pensé que era bueno señalar por las dudas. Lo siento si fue engañoso. –

1

En mi experiencia con LINQ to SQL, he llegado a la conclusión, por varias razones, de que LINQ está utilizando la reflexión para establecer y obtener valores de campo en instancias de clase de entidad. No sé si puedo recordar todas las razones, pero esto es lo que puedo decirte.

  1. Si no recuerdo mal, LINQ no llama ningún procedimientos de propiedad, pero se pone directamente y lee todos los valores de los campos privados directamente, lo que sólo puede hacerse a través de la reflexión, por lo que yo sé.
  2. Los nombres proporcionados por los MetaData (en los atributos de las propiedades de clase de entidad) proporcionan información de nombre de campo en forma de cadena (si la columna de la base de datos y el nombre de propiedad son diferentes, por ejemplo). A partir de esto, puede concluir que LINQ debe usar el reflejo para buscar al miembro y acceder a él.

Creo que hace esto para imponer la simplicidad: puede confiar en los valores en los campos de la clase de entidad reflejando directamente los valores de columna de la base de datos, y no hay demasiados gastos para recuperar el objeto de la base de datos (rellenando una entidad recién creada para corresponder con los valores recuperados de la base de datos no debe enrutarse a través de procedimientos de propiedad). Una cosa que he hecho para representar valores enumerados recuperados de la base de datos, por ejemplo, es hacer que algunas de las propiedades generadas por LINQ sean privadas y envolverlas en una propiedad codificada manualmente en una clase parcial que lee y escribe la propiedad LINQ.

Cuestiones relacionadas