Compartir a través de


Enlace de datos (LINQ to SQL)

Actualización: November 2007

LINQ to SQL admite el enlace a controles comunes, como controles de cuadrícula. Concretamente, LINQ to SQL define los modelos básicos para realizar un enlace a una cuadrícula de datos y controlar el enlace de detalles principales, tanto para la visualización como para la actualización.

Principio subyacente

LINQ to SQL convierte las consultas LINQ a SQL para su ejecución en una base de datos. Los resultados son IEnumerable con establecimiento inflexible de tipos. 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 formularios 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 (formularios 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:

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

Lo mismo sucede con Windows Presentation Foundation:

Dim listView1 As New ListView()
Dim custQuery2 = _
From cust In db.Customers _
Select cust

Dim ItemsSource As New ListViewItem
ItemsSource = custQuery2
ListView listView1 = new ListView();
var custQuery2 =
    from cust in db.Customers
    select cust;

ListViewItem ItemsSource = new ListViewItem();
ItemsSource = (ListViewItem)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 objeto Table<TEntity> subyacente, el origen no permite la edición (por ejemplo, groupby). LINQ to SQL examina la consulta para rellenar un elemento SortableBindingList genérico, que es un objeto BindingList<T> simple que implementa la característica de ordenación para las entidades T de una propiedad determinada.

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. ApplySort llama a ApplySortCore 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 operaciones 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:

Almacenamiento en caché

Las consultas LINQ to SQL implementan GetList. Cuando la clase BindingSource de formularios 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 sólo campos no es suficiente. Los formularios Windows Forms requieren que se utilicen.

  • De forma predeterminada, los tipos de base de datos image, varbinary y timestamp se asignan a una matriz de bytes. Dado que ToString() 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.

Vea también

Otros recursos

Información general (LINQ to SQL)