Partager via


Liaison de données

LINQ to SQL prend en charge la liaison aux contrôles communs, tels que les contrôles de grille. Plus précisément, LINQ to SQL définit les modèles de base pour créer une liaison avec une grille de données et gérer la liaison maître/détail en termes d’affichage et de mise à jour.

Principe sous-jacent

LINQ to SQL traduit des requêtes LINQ en SQL pour les exécuter sur une base de données. Les résultats sont des IEnumerable fortement typés. Étant donné que ces objets sont des objets Common Language Runtime (CLR) ordinaires, la liaison de données d'objet ordinaire peut être utilisée pour afficher les résultats. En revanche, les opérations de modification (insertions, mises à jour et suppressions) requièrent des étapes supplémentaires.

Opération

La liaison implicite aux contrôles Windows Forms s’effectue en implémentant IListSource. Les sources de données génériques Table<TEntity> (Table<T> en C# ou Table(Of T) en Visual Basic) et génériques DataQuery ont été mises à jour pour implémenter IListSource. Les moteurs de liaison de données de l'interface utilisateur (UI) (Windows Forms et Windows Presentation Foundation) effectuent tous les deux un test pour vérifier si leur source de données implémente IListSource. Par conséquent, l’écriture d’une affectation directe d’une requête à une source de données d’un contrôle appelle de façon implicite la génération de collection LINQ to SQL, comme dans l’exemple suivant :

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

Cela s'applique également à 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

Les générations de collection sont implémentées par le Table<TEntity> générique et le DataQuery générique dans GetList.

Implémentation IListSource

LINQ to SQL implémente IListSource dans deux emplacements :

  • La source de données est un Table<TEntity> : LINQ to SQL parcourt la table pour remplir une collection DataBindingList qui garde une référence dans la table.

  • La source de données est un IQueryable<T>. Il existe deux scénarios :

    • Si LINQ to SQL trouve le Table<TEntity> sous-jacent à partir de IQueryable<T>, la source autorise l’édition et la situation est identique à celle du premier point de la liste à puces.

    • Si LINQ to SQL ne trouve pas le Table<TEntity> sous-jacent, la source n’autorise pas l’édition (par exemple, groupby). LINQ to SQL parcourt la requête pour remplir un SortableBindingListgénérique, qui est un simple BindingList<T> qui implémente la fonctionnalité de tri pour les entités T pour une propriété donnée.

Collections spécialisées

Pour de nombreuses fonctionnalités décrites précédemment dans ce document, BindingList<T> a été spécialisé pour quelques classes différentes. Ces classes sont le SortableBindingList et le DataBindingList génériques. Les deux sont déclarés comme internes.

SortableBindingList générique

Cette classe hérite de BindingList<T>et est une version triable de BindingList<T>. Le tri est une solution en mémoire et ne contacte jamais la base de données elle-même. BindingList<T> implémente IBindingList, mais ne prend pas en charge le tri par défaut. Toutefois, BindingList<T> implémente IBindingList avec les méthodes principales virtuelles. Vous pouvez facilement substituer ces méthodes. Le SortableBindingList générique substitue SupportsSortingCore, SortPropertyCore, SortDirectionCore et ApplySortCore. ApplySortCore est appelé par ApplySort et trie la liste d'éléments T pour une propriété donnée.

Une exception est levée si la propriété n'appartient pas à T.

Pour effectuer le tri, LINQ to SQL crée une classe SortableBindingList.PropertyComparer générique qui hérite de IComparer.Compare générique et implémente un comparateur par défaut pour un type T donné, un PropertyDescriptor et une direction. Cette classe crée dynamiquement un Comparer de T où T est le PropertyType de PropertyDescriptor. Puis le comparateur par défaut est récupéré du Comparer générique statique. Une instance par défaut est obtenue en utilisant la réflexion.

Le SortableBindingList générique est également la classe de base pour DataBindingList. Le SortableBindingList générique propose deux méthodes virtuelles pour interrompre ou continuer le suivi des ajouts/suppressions d'éléments. Ces deux méthodes peuvent être utilisées pour les fonctionnalités de base telles que le tri, mais seront réellement implémentées par les classes supérieures telles que le DataBindingList générique.

DataBindingList générique

Cette classe hérite du SortableBindingLIst générique. Le DataBindingList générique garde une référence au Table générique sous-jacent de l'IQueryable générique utilisé pour remplir la première fois la collection. Le DatabindingList générique ajoute le suivi des ajouts/suppressions d'élément à la collection en substituant InsertItem() et RemoveItem(). Il implémente également la fonctionnalité récapitulative de suivi des interruptions/reprises pour rendre le suivi conditionnel. Avec cette fonctionnalité, le DataBindingList générique tire parti de toute l’utilisation polymorphe de la fonctionnalité de suivi des classes parentes.

Création d’une liaison à EntitySets

La création d’une liaison avec EntitySet est un cas spécial parce que EntitySet est déjà une collection qui implémente IBindingList. LINQ to SQL ajoute la prise en charge du tri et de l’annulation (ICancelAddNew). Une classe EntitySet utilise une liste interne pour stocker des entités. Cette liste est une collection de bas niveau basée sur un tableau générique, la classe ItemList générique.

Ajout d’une fonctionnalité de tri

Les tableaux proposent une méthode de tri (Array.Sort()) que vous pouvez utiliser avec un Comparer de T. LINQ to SQL utilise la classe SortableBindingList.PropertyComparer générique décrite précédemment dans cette rubrique pour obtenir ce Comparer et effectuer le tri en fonction de la propriété et de la direction. Une méthode ApplySort est ajoutée à l’ItemList générique pour appeler cette fonctionnalité.

Du côté du EntitySet, vous devez désormais déclarer la prise en charge du tri :

Lorsque vous utilisez un System.Windows.Forms.BindingSource et liez un EntitySet<TEntity> à System.Windows.Forms.BindingSource.DataSource, vous devez appeler EntitySet<TEntity>.GetNewBindingList pour mettre à jour BindingSource.List.

Si vous utilisez un System.Windows.Forms.BindingSource et définissez la propriété BindingSource.DataMember, puis affectez à BindingSource.DataSource une classe qui a une propriété nommée dans le BindingSource.DataMember qui expose EntitySet<TEntity>, vous ne devez pas appeler EntitySet<TEntity>.GetNewBindingList pour mettre à jour BindingSource.List, mais vous perdez la fonction de tri.

Mise en cache

Les requêtes LINQ to SQL implémentent GetList. Lorsque la classe BindingSource Windows Forms rencontre cette interface, elle appelle GetList() trois fois pour une seule connexion. Pour éviter cette situation, LINQ to SQL implémente un cache par instance pour stocker et toujours retourner la même collection générée.

Annulation

IBindingList définit une méthode AddNew utilisée par les contrôles pour créer un élément à partir d'une collection liée. Le contrôle DataGridView présente très bien cette fonctionnalité lorsque la dernière ligne visible contient une étoile dans son en-tête. L'étoile vous indique que vous pouvez ajouter un nouvel élément.

Outre cette fonctionnalité, une collection peut également implémenter ICancelAddNew. Cette fonctionnalité autorise les contrôles à annuler ou valider le fait que le nouvel élément modifié ait été validé ou pas.

ICancelAddNew est implémenté dans toutes les collections LINQ to SQL liées aux données (SortableBindingList générique et EntitySet générique). Dans les deux implémentations, le code s'applique comme suit :

  • Permet l’insertion des éléments, puis leur suppression de la collection.

  • N’effectue pas le suivi des modifications tant que l’interface utilisateur ne valide pas l’édition.

  • N'effectue pas le suivi des modifications tant que l'édition est annulée (CancelNew).

  • Autorise le suivi lorsque l’édition est validée (EndNew).

  • Permet à la collection de se comporter normalement si le nouvel élément ne provient pas de AddNew.

Dépannage

Cette section appelle plusieurs éléments qui peuvent vous aider à dépanner les applications de liaison de données LINQ to SQL.

  • Vous devez utiliser des propriétés ; l'utilisation de champs uniquement n'est pas suffisante. C'est une exigence des Windows Forms.

  • Par défaut, les types de bases de données image, varbinary et timestamp mappent au tableau d’octets. Comme ToString() n'est pas pris en charge dans ce scénario, ces objets ne peuvent pas être affichés.

  • Un membre de classe mappé à une clé primaire a un accesseur Set, mais LINQ to SQL ne prend pas en charge les modifications de l’identité d’objet. Par conséquent, la clé primaire/unique utilisée dans le mappage ne peut pas être mise à jour dans la base de données. Une modification dans la grille provoque une exception lorsque vous appelez SubmitChanges.

  • Si une entité est liée dans deux grilles distinctes (par exemple, une grille principale et une grille de détail), une opération Delete dans la grille principale n'est pas propagée à la grille de détail.

Voir aussi