Enlace de datos
LINQ to SQL admite el enlace a controles comunes, como controles de cuadrícula. Concretamente,LINQ to SQL define los patrones básicos para realizar un enlace a una cuadrícula de datos y controlar el enlace de detalles principales, tanto para la presentación como para la actualización.
Principio subyacente
LINQ to SQL traduce las consultas de LINQ a SQL para su ejecución en una base de datos. Los resultados son IEnumerable
fuertemente tipados. Dado que se trata de objetos CLR (Common Language Runtime) normales, se puede usar el enlace de datos de objeto normal para mostrar los resultados. Por otro lado, las operaciones de cambio (inserciones, actualizaciones y eliminaciones) requieren pasos adicionales.
Operación
El enlace implícito a controles de Windows Forms se logra mediante la implementación de IListSource. Los elementos genéricos Table<TEntity> (Table<T>
en C# o Table(Of T)
en Visual Basic) y DataQuery
de los orígenes de datos se han actualizado para implementar IListSource. Los motores de enlace de datos de la interfaz de usuario (Windows Forms y Windows Presentation Foundation) comprueban si su origen de datos implementa IListSource. Por consiguiente, al escribir una modificación directa de una consulta en un origen de datos de un control, se llama implícitamente a la generación de colecciones de LINQ to SQL, como en el ejemplo siguiente:
DataGrid dataGrid1 = new DataGrid();
DataGrid dataGrid2 = new DataGrid();
DataGrid dataGrid3 = new DataGrid();
var custQuery =
from cust in db.Customers
select cust;
dataGrid1.DataSource = custQuery;
dataGrid2.DataSource = custQuery;
dataGrid2.DataMember = "Orders";
BindingSource bs = new BindingSource();
bs.DataSource = custQuery;
dataGrid3.DataSource = bs;
Dim dataGrid1 As New DataGrid()
Dim dataGrid2 As New DataGrid()
Dim dataGrid3 As New DataGrid()
Dim custQuery = _
From cust In db.Customers _
Select cust
dataGrid1.DataSource = custQuery
dataGrid2.DataSource = custQuery
dataGrid2.DataMember = "Orders"
Dim bs = _
New BindingSource()
bs.DataSource = custQuery
dataGrid3.DataSource = bs
Lo mismo sucede con Windows Presentation Foundation:
ListView listView1 = new ListView();
var custQuery2 =
from cust in db.Customers
select cust;
ListViewItem ItemsSource = new ListViewItem();
ItemsSource = (ListViewItem)custQuery2;
Dim listView1 As New ListView()
Dim custQuery2 = _
From cust In db.Customers _
Select cust
Dim ItemsSource As New ListViewItem
ItemsSource = custQuery2
Las generaciones de colecciones se implementan mediante Table<TEntity> genérico y DataQuery
genérico en GetList.
Implementación de IListSource
LINQ to SQL implementa IListSource en dos ubicaciones:
El origen de datos es Table<TEntity>:LINQ to SQL examina la tabla para rellenar una colección
DataBindingList
que mantiene una referencia en la tabla.El origen de datos es IQueryable<T>. Hay dos escenarios:
Si LINQ to SQL encuentra el objeto Table<TEntity> subyacente de IQueryable<T>, el origen permite la edición y la situación es la misma que en el primer punto de la lista.
Si LINQ to SQL no encuentra el subyacente Table<TEntity>, el origen no permite la edición (por ejemplo,
groupby
). LINQ to SQL busca la consulta para rellenar unSortableBindingList
genérico, que es un simple BindingList<T> que implementa la característica ordenada para entidades de tipo T de una propiedad en concreto.
Colecciones especializadas
Para muchas de las características antes descritas en este documento, BindingList<T> se ha especializado en algunas clases diferentes. Estas clases son SortableBindingList
genérica y DataBindingList
genérica. Ambas se declaran como internas.
SortableBindingList genérica
Esta clase se hereda de BindingList<T> y es una versión de BindingList<T> que se puede ordenar. La ordenación es una solución en memoria y nunca entra en contacto con la propia base de datos. BindingList<T> implementa IBindingList, pero no admite la ordenación de forma predeterminada. Sin embargo, BindingList<T> implementa IBindingList con los métodos básicos virtuales. Puede invalidar estos métodos con facilidad. La clase SortableBindingList
genérica invalida SupportsSortingCore, SortPropertyCore, SortDirectionCore y ApplySortCore. ApplySortCore
llama a ApplySort y ordena la lista de elementos T de una propiedad dada.
Se producirá una excepción si la propiedad no pertenece a T.
Para la operación de ordenación,LINQ to SQL crea una clase SortableBindingList.PropertyComparer
genérica que hereda del método genérico IComparer.Compare e implementa un comparador predeterminado para un tipo T dado, un objeto PropertyDescriptor
y una dirección. Esta clase crea dinámicamente un Comparer
de T, donde T es PropertyType
de PropertyDescriptor
. Después, el comparador predeterminado se recupera del Comparer
genérico estático. Se obtiene una instancia predeterminada mediante reflexión.
La clase SortableBindingList
genérica es también la clase base para DataBindingList
. La clase SortableBindingList
genérica proporciona dos métodos virtuales para suspender o reanudar el seguimiento de las operaciones de agregar o quitar elementos. Esos dos métodos se pueden utilizar para características básicas, como la ordenación, pero realmente serán implementados por clases de nivel superior, como la clase DataBindingList
genérica.
Clase DataBindingList genérica
Esta clase se hereda de la clase SortableBindingLIst
genérica. La clase DataBindingList
genérica mantiene una referencia en el elemento Table
genérico subyacente de la interfaz genérica IQueryable
que se utilizó para el llenado inicial de la colección. La clase DatabindingList
genérica agrega el seguimiento de las operaciones de agregar o quitar elementos a la colección mediante la invalidación de InsertItem
() y RemoveItem
(). También implementa la característica de seguimiento de suspensión/reanudación abstracta para que el seguimiento sea condicional. Esta característica permite que la clase DataBindingList
genérica se pueda aprovechar del uso polimórfico completo de la característica de seguimiento de las clases primarias.
Enlace a EntitySets
El enlace a EntitySet
es un caso especial, porque EntitySet
ya es una colección que implementa IBindingList. LINQ to SQL agrega compatibilidad con las operaciones de ordenación y cancelación (ICancelAddNew). Una clase EntitySet
utiliza una lista interna para almacenar las entidades. Esta lista es una colección de nivel inferior basada en una matriz genérica, la clase ItemList
genérica.
Agregar una característica de ordenación
Las matrices proporcionan un método de ordenación (Array.Sort()
) que se puede utilizar con un Comparer
de T. LINQ to SQL utiliza la clase genérica SortableBindingList.PropertyComparer
descrita anteriormente en este tema para obtener el Comparer
de la propiedad y la dirección de ordenación. Para llamar a esta característica, se agrega un método ApplySort
a la clase ItemList
genérica.
En el lado EntitySet
, ahora tiene que declarar la compatibilidad con la ordenación:
SupportsSorting devuelve
true
.ApplySort llama a
entities.ApplySort()
y después aOnListChanged()
.Las propiedades SortDirection y SortProperty exponen la definición de la ordenación actual, que se almacena en miembros locales.
Cuando use una clase System.Windows.Forms.BindingSource y enlace un tipo EntitySet<TEntity> a la propiedad System.Windows.Forms.BindingSource.DataSource, debe llamar al método EntitySet<TEntity>.GetNewBindingList para actualizar la clase BindingSource.List.
Si usa una clase System.Windows.Forms.BindingSource y establece las propiedades BindingSource.DataMember y BindingSource.DataSource en una clase con una propiedad citada en la propiedad BindingSource.DataMember que expone EntitySet<TEntity>, no tiene que llamar al método EntitySet<TEntity>.GetNewBindingList con el fin de actualizar la clase BindingSource.List, pero pierde capacidad de ordenación.
Almacenamiento en memoria caché
Implementación GetList de consultas de LINQ to SQL. Cuando la clase BindingSource de Windows Forms se encuentra con esta interfaz, llama a GetList() tres veces para la misma conexión. Para evitar esta situación,LINQ to SQL implementa una caché por cada instancia para almacenar y devolver siempre la misma colección generada.
Cancelación
IBindingList define un método AddNew que los controles utilizan para crear un nuevo elemento a partir de una colección enlazada. El control DataGridView
muestra esta característica perfectamente, incluyendo un asterisco en el encabezado de la última fila visible. El asterisco indica que se puede agregar un nuevo elemento.
Además de esta característica, una colección también puede implementar ICancelAddNew. Esta característica permite a los controles cancelar o verificar la validación o no validación del nuevo elemento editado.
ICancelAddNew se implementa en todas las colecciones de LINQ to SQL enlazadas a datos (SortableBindingList
genérica y EntitySet
genérica). En ambas implementaciones, el código actúa de la forma siguiente:
Permite insertar y después quitar los elementos de la colección.
No realiza un seguimiento de los cambios hasta que la interfaz de usuario confirma la edición.
No realiza un seguimiento de los cambios hasta que la edición se cancela (CancelNew).
Permite el seguimiento de los cambios cuando se confirma la edición (EndNew).
Permite que la colección se comporte con normalidad si el nuevo elemento no procede de AddNew.
Solución de problemas
En esta sección se describen varios elementos que podrían ayudarle a solucionar los problemas de las aplicaciones de enlace de datos de LINQ to SQL.
Debe utilizar propiedades; utilizar solo campos no es suficiente. Los Windows Forms requieren que se utilicen.
De forma predeterminada, los tipos de base de datos
image
,varbinary
ytimestamp
se asignan a una matriz de bytes. Dado queToString()
no se admite en este escenario, estos objetos no se pueden mostrar.Un miembro de clase asignado a una clave principal tiene un establecedor, pero LINQ to SQL no admite el cambio de identidad del objeto. Por consiguiente, la clave principal/única que se usa en la asignación no se puede actualizar en la base de datos. Un cambio en la cuadrícula produce una excepción al llamar a SubmitChanges.
Si una entidad está enlazada en dos cuadrículas independientes (por ejemplo, una maestra y otra de detalle),
Delete
en la cuadrícula maestra no se propaga a la cuadrícula de detalle.