Partager via


Classes d’entité

Dernière modification : mardi 9 mars 2010

S’applique à : SharePoint Foundation 2010

Dans cet article
Utilisation de SPMetal
Classe du contexte de données
Listes, types de contenu et éléments de liste

Cette rubrique présente les classes d’entité du fournisseur LINQ to SharePoint. Ces classes fournissent une interface relationnelle-objet légère entre votre code Microsoft Visual Basic ou C# orienté objet et la structure de table relationnelle des bases de données de contenu de Microsoft SharePoint Foundation. Elles fournissent également les bases du système de suivi des modifications d’objets.

L’interface relationnelle-objet autorise du code orienté objet dans des requêtes LINQ et permet également la création, la suppression et la mise à jour d’éléments de liste à l’aide de code orienté objet qui référence les entités de base de données indépendamment du modèle objet SharePoint Foundation ordinaire. De plus, une fois l’infrastructure relationnelle-objet mise en place, vous pouvez l’utiliser pour la logique métier orientée objet dans tous les cas où le chargement différé et léger fourni par l’infrastructure offre des avantages par rapport au modèle objet SharePoint Foundation ordinaire. Utiliser les classes d’entité au lieu du modèle objet ordinaire peut également améliorer la lisibilité du code lorsque la référence de contenu se trouve à proximité du code de requête LINQ utilisant les mêmes classes d’entité, comme dans une boucle foreach itérant le résultat d’une requête LINQ.

Utilisation de SPMetal

Comme l’écriture des classes traitées dans cet article peut être fastidieuse et sujette à erreurs, SharePoint Foundation contient SPMetal, outil en ligne de commande, qui peut être utilisé pour générer les déclarations de classe et de propriété. Il lit les définitions de type de contenu et les schémas des listes d’un site Web SharePoint Foundation cible, puis génère les classes d’entité, notamment les décorations d’attribut, à partir de ceux-ci. L’outil est inclus dans SharePoint Foundation et il se trouve généralement dans le dossier BIN de %ProgramFiles%\Common Files\Microsoft Shared\web server extensions\14\. Il est recommandé de l’utiliser.

Vous pouvez personnaliser le mode de génération du code par SPMetal. De plus, comme toutes les classes qu’il génère sont marquées comme partial (Partial en Visual Basic), vous pouvez leur ajouter des membres dans un fichier de code distinct. Si vous devez générer de nouveau les classes d’entité à l’aide de SPMetal, seul le fichier généré est remplacé et non celui avec les membres personnalisés. Pour plus d’informations sur l’utilisation de SPMetal, voir Procédure : utiliser SPMetal.

ConseilConseil

Il est recommandé d’utiliser l’outil SPMetal pour générer toutes les déclarations des classes traitées dans cet article. De plus, les exemples de code contenus dans cet article ne sont pas destinés à être copiés dans votre propre code et ne sont pas des copies exactes du code qui serait généré par SPMetal. Chaque exemple a été simplifié en supprimant le code étant sans rapport avec le sujet abordé. Plus particulièrement, tout code lié au système de suivi des modifications d’objets a été supprimé de ces exemples. Pour plus d’informations sur le système et le code de support, voir Suivi des modifications d’objets et accès concurrentiel optimiste. Les décorations d’attribut sur les déclarations de classe et de propriété présentées dans cette rubrique sont également plus simples que dans la réalité et certains attributs sont complètement omis. Pour plus d’informations sur les attributs et leurs utilisations, voir les rubriques de référence pour les classes suivantes (et leurs membres) :

Classe du contexte de données

Au sommet de la hiérarchie des classes d’entité se trouve la classe DataContext qui représente le contenu d’un site Web. Vous pouvez instancier un objet DataContext en passant à son constructeur l’URL du site Web dont vous souhaitez modéliser les données. Vous devez ensuite appeler sa méthode GetList<T>(String) pour obtenir une référence à une liste spécifique. Voici un exemple :

DataContext teamData = new DataContext("http://DeptServer/TeamSite")
EntityList<Announcment> teamAnns = teamData.GetList<Announcement>("Announcements");

En supposant que vous avez déclaré une classe pour représenter le type de contenu « Announcement » (Annonce) (voir ci-après), vous pourriez ensuite interroger teamAnns. Voici un exemple :

var excitingAnns = from ann in teamAnns
                   where ann.Title.EndsWith("!")
                   select ann;

En règle générale, vous pouvez obtenir du code appelant plus lisible et plus orienté objet si vous déclarez une classe qui hérite de la classe DataContext et possède une propriété pour chacune des listes du site Web. Voici un exemple de telles déclarations :

public partial class TeamSite : DataContext 
{
    public TeamSite(string requestUrl) : 
        base(requestUrl) { }

    [List(Name="Announcements")]
    public EntityList<Announcement> Announcements 
    {
        get { return this.GetList<Announcement>("Announcements"); }
    }

}

Notes

La classe ListAttribute identifie la propriété comme représentant une liste spécifiée du site Web qui est représentée par l’objet DataContext.

Une fois cette déclaration en place, le code appelant n’a pas besoin de l’appel explicite de la méthode GetList<T>(String) et est plus auto-documenté.

TeamSite teamData = new TeamSite("http://DeptServer/TeamSite");

var excitingAnns = from ann in teamData.Announcements
                   where ann.Title.EndsWith("!")
                   select ann;

Important

Le constructeur de la classe TeamSite ne charge pas toute la liste Announcements (Annonces). La classe EntityList<TEntity> prend en charge le chargement différé. Les objets de ce type ne sont pas chargés tant qu’ils ne sont pas référencés de façon explicite dans du code ultérieur.

L’outil SPMetal génère toujours une classe qui dérive de DataContext. Vous pouvez configurer les listes qu’il modélise. Par défaut, il déclare une propriété pour chaque liste non masquée du site Web.

Notes

Vous pouvez bien sûr ajouter des méthodes, des événements, des champs et des propriétés qui ne représentent pas des listes à votre classe dérivée de DataContext. Si vous ajoutez de telles méthodes, vos déclarations doivent figurer dans un fichier de code distinct de celui généré par SPMetal. Votre code ne sera pas ainsi remplacé si vous devez générer de nouveau le code produit par SPMetal.

Listes, types de contenu et éléments de liste

Toute solution qui a recours à LINQ to SharePoint doit utiliser les classes d’entité pour représenter les listes, types de contenu et éléments de liste SharePoint.

La classe EntityList<TEntity> représente une liste SharePoint Foundation. La variable de type, TEntity, correspond au type des éléments de liste, c’est à dire au type de contenu. Une propriété du type EntityList<TEntity> se voit attribuer le même nom que la liste qu’elle représente, telle que « Announcements » ou « Calendar » (Calendrier). En règle générale, la variable de type porte le même nom mais au singulier, par exemple, « Announcement ». Si le nom de la liste est au singulier, un autre nom peut être toutefois utilisé. « CalendarEvent » (ÉvénementCalendrier), par exemple, est utilisé comme type de la classe représentant une liste des calendriers. Pour une liste personnalisée, le nom de type est construit en concaténant le nom de liste avec le terme « Item » (Élément). Une liste « Livres » personnalisée, par exemple, se voit attribuer le type « BooksItem » (ÉlementLivres). La classe EntityList<TEntity> est scellée et ne possède pas de constructeur public. Reportez-vous à la section intitulée Classe du contexte de données pour obtenir un exemple de déclaration d’une propriété en type EntityList<TEntity> pour une variable de type TEntity spécifique.

Les types de contenu doivent eux-mêmes être déclarés en tant que classes. La déclaration est décorée avec un ContentTypeAttribute (dont le nom peut être raccourci en « ContentType »), comme illustré dans l’exemple ci-après.

[ContentType(Name="Announcement" Id="Ox0104")]
public partial class Announcement
{

}

Chaque champ (et propriété de métadonnées) d’une liste doit être représenté avec une propriété publique dans la définition de classe de type de contenu si vous devez référencer de manière explicite le champ (ou la propriété) dans une requête ou un autre code. Comme ces classes peuvent avoir d’autres propriétés, celles qui représentent les champs (et les propriétés de métadonnées) sont différenciées par la décoration [ColumnAttribute] (qui peut être raccourcie en [Column]), comme illustré dans l’exemple ci-après.

[ContentType(Name="Customer")]
public partial class Customer : Item
{
    [Column]
    public Int32 CustomerId { get; set; }

    [Column]
    public String Name { get; set; }
}
Note AttentionAttention

Si le schéma de liste est modifié une fois les classes d’entité générées, une solution utilisant ces dernières risque de ne pas fonctionner.

Héritage des types de contenu

Les classes de contenu peuvent refléter les relations d’héritage des types de contenu qu’elles représentent. Le type de contenu fondamental de SharePoint Foundation est appelé Élément. Il fournit les champs de base que possèdent tous les éléments de liste, comme Titre. (Certains de ces champs de base, tels que ID et Version, sont masqués par défaut dans les affichages de liste SharePoint Foundation standard.) Voici une version simplifiée de la déclaration de classe pour le type de contenu Item :

[ContentType(Name="Item")]
public partial class Item
{
    private Nullable<Int32> _id;
    private Nullable<Int32> _version;
    private String _title;

    [Column]
    public Nullable<Int32> Id { get; set; }

    [Column]
    public Nullable<Int32> Version { get; set; }

    [Column]
    public String Title { get; set; }

  // Other member declarations omitted for readability.
}

Toutes les autres classes de type de contenu dérivent de la classe Item. Elles ne doivent donc pas déclarer de manière explicite les propriétés qu’elles héritent.

Relations entre les listes et chargement différé

Les listes peuvent avoir des relations permanentes entre elles. Celles-ci sont représentées dans l’infrastructure relationnelle-objet par AssociationAttribute et par les classes EntityRef<TEntity> et EntitySet<TEntity> qui, comme EntityList<TEntity>, diffèrent le chargement de l’entité qu’elles représentent jusqu’au premier accès à l’entité à l’exécution. (Éventuellement, un objet LookupList<T> est également impliqué dans la représentation de la relation.)

Important

Dans SharePoint Foundation, deux listes ne peuvent être associées que si l’une des listes possède une colonne de recherche dans une colonne de l’autre liste.

Références d’entité

La classe EntityRef<TEntity> représente l’élément de liste du côté « un » d’une relation plusieurs-à-un ou un-à-un entre des éléments de liste de différentes listes et permet un chargement différé de celui-ci. Supposons par exemple que chaque membre d’une équipe se voit affecter un code de sécurité stocké dans une liste distincte de celle des membres d’équipe pour des raisons de sécurité. Une classe TeamMember représente le type des éléments de la liste Team Members (Membres d’équipe) et une classe SecurityCode, celui des éléments de la liste Security Codes (Codes de sécurité). Comme exactement un code de sécurité est destiné à chaque membre, la classe TeamMember déclare un champ private de type EntityRef<TEntity> (où la variable de type TEntity représente SecurityCode) qui représente un élément de la liste Security Codes. La classe TeamMember déclare également une propriété public de type SecurityCode qui enveloppe le champ privé. C’est cette propriété qui est décorée avec AssociationAttribute. Lorsqu’un objet de type TeamMember est instancié, sa valeur SecurityCode n’est pas immédiatement chargée. Elle n’est chargée que si elle est référencée dans du code ultérieur.

L’exemple ci-après montre les parties pertinentes de la déclaration de la classe TeamMember. Notez les points suivants concernant cet exemple :

  • La relation entre les deux tables est déclarée avec la décoration AssociationAttribute. (L’utilisation de la classe EntityRef<TEntity> permet le chargement différé, mais n’établit pas une relation de liste.)

  • La propriété MultivalueType de AssociationAttribute spécifie si chaque élément doit avoir un seul ou plusieurs éléments correspondants dans la liste associée.

  • La propriété List de la classe AssociationAttribute spécifie le nom respectant la casse de la liste associée.

[ContentType(Name = "TeamMember")]
public class TeamMember
{
    private EntityRef<SecurityCode> memberSecurityCode;

    [Association(List = "SecurityCodes", MultiValueType = AssociationType.Single)]
    public SecurityCode MemberSecurityCode
    {
        get { return memberSecurityCode.GetEntity(); }
        set { memberSecurityCode.SetEntity(value); }
    }

    // Declarations of other members suppressed for readability.
}

[ContentType(Name = "SecurityCode")]
public class SecurityCode
{
    [Column]
    public String Value { get; set; }

    // Declarations of other members suppressed for readability.
}

Notes

Les assesseurs get et set de la propriété MemberSecurityCode utilisent les méthodes GetEntity() et SetEntity(TEntity) au lieu du code d’assesseur plus familier (« return securityCode » et « securityCode=value »), car la propriété est d’un type différent du champ qu’elle encapsule. Ces deux méthodes accèdent à l’objet EntityRef<TEntity> pour atteindre l’objet SecurityCode qu’il encapsule.

Vous pouvez maintenant accéder au code de sécurité d’un membre d’équipe avec la notation par points orientée objet, et l’association peut fonctionner dans les requêtes comme une sorte de jointure permanente des deux listes. Par exemple, dans la requête ci-dessous, member est un élément de la liste Team Members, mais MemberSecurityCode est une référence à un élément de la liste Security Codes (Codes de sécurité).

var result = from member in teamMembers
             where member.MemberSecurityCode.Value.Contains("guest")
             select member;

La relation peut être définie dans la classe qui représente le type de contenu source de la recherche ou celle qui représente le type de contenu cible. Voici comment vous définiriez la relation entre les listes Team Members et Security Codes à l’aide d’une propriété de la classe SecurityCode.

[ContentType(Name = "SecurityCode")]
public partial class SecurityCode
{
    [Column]
    public String Value { get; set; }

    private EntityRef<TeamMember> teamMember;

    [Association(List = "TeamMembers", MultiValueType = AssociationType.Single)]
    public TeamMember TeamMember
    {
        get { return this.teamMember.GetEntity(); }
        set { this.teamMember.SetEntity(value); }
    }
    // Other member declarations suppressed for readability.
}

Déclarer de cette manière la relation dans la classe cible permet des recherches inversées dans le code appelant. Vous pouvez même déclarer la relation dans les deux classes pour permettre des recherches dans les deux sens. Pour plus d’informations sur les recherches inversées, voir la section Recherches inversées plus loin dans cet article.

Jeux d’entités

La classe EntitySet<TEntity> représente le côté « plusieurs » d’une relation plusieurs-à-un ou plusieurs-à-plusieurs entre des éléments de liste de différentes listes et permet son chargement différé. Supposons, par exemple, que chaque membre d’une équipe se voit affecter plusieurs projets et que chaque projet soit affecté à plusieurs membres. Il s’agit d’une relation plusieurs-à-plusieurs. Une classe TeamMember représente le type des éléments de la liste Team Members et une classe Project, celui des éléments de la liste Projects. La classe TeamMember déclare un champ private de type EntitySet<TEntity> (où TEntity représente Project) qui représente un ou plusieurs éléments de la liste Projects. Le champ est encapsulé avec une propriété public EntitySet<Project> appelée AssignedProjects. Lorsqu’un objet de type TeamMember est instancié, l’objet référencé par cette propriété AssignedProjects n’est pas immédiatement chargé. Il est chargé uniquement s’il est référencé dans du code ultérieur.

[ContentType(Name = "TeamMember")]
public class TeamMember
{
    private EntitySet<Project> assignedProjects;

    [Association(List="Projects", MultiValueType=AssociationType.Multi)]
    public EntitySet<Project> AssignedProjects
    {
        get { return this.assignedProjects; }
        set { this.assignedProjects.Assign(value); }
    }

    // Declarations of other members suppressed for readability.
}

[ContentType(Name = "Project")]
public class Project
{
    [Column]
    public String Title { get; set; }

    // Declarations of other members suppressed for readability.
}

Notes

L’exemple de code précédent, ainsi que tout autre exemple illustrant la classe Project, contient une déclaration de propriété Title pour représenter la colonne Title (Titre). Il s’agit d’une simplification à des fins de lisibilité. Dans le code réel, la classe Project hériterait d’une classe Item représentant le type de contenu de base de SharePoint Foundation. Comme la propriété Title est déclarée dans la définition de la classe Item, elle ne devrait pas se trouver dans la définition de la classe Project.

Ces déclarations mises en place, vous pouvez rechercher les membres d’équipe auxquels est affecté un projet spécifique, comme dans l’exemple ci-après.

Project fiscalPlan = new Project() { Title="Fiscal year planning." };

TeamSite teamData = new TeamSite("http://DeptServer/TeamSite");

var filteredTeamMembers = from member in teamData.TeamMembers
                          where member.AssignedProjects.Contains(fiscalPlan) 
                          select member;

Comme dans le cas de l’exemple de EntityRef<TEntity>, l’une des deux classes représentant les types de contenu des deux listes liées peut être utilisée pour définir la relation. L’exemple ci-dessous montre comment serait déclarée la même relation Team Members-à-Projects dans la classe Project.

[ContentType(Name = "Project")]
public class Project
{
    [Column]
    public String Title { get; set; }

    private EntitySet<TeamMember> assignedTeamMembers;

    [Association(List="Team Members", MultivalueType=AssociationType.Multi)]
    public EntitySet<TeamMember> AssignedTeamMembers
    {
        get { return this.assignedTeamMembers; }
        set { this.assignedTeamMembers.Assign(value); }
    }

    // Declarations of other members suppressed for readability.
}

Vous pouvez déclarer la relation dans les deux classes. Pour plus d’informations, voir la section Recherches inversées ci-après.

Relations un-à-plusieurs et plusieurs-à-un

La section Références d’entité contient un exemple de codage d’une relation un-à-un entre des listes. La section Jeux d’entités contient, quant à elle, un exemple de codage d’une relation plusieurs-à-plusieurs. Il est possible de représenter également des relations un-à-plusieurs et plusieurs-à-un. Pour poursuivre l’exemple de la section Jeux d’entités, imaginons que chaque membre d’équipe ne se voit pas seulement affecter plusieurs projets, mais est aussi responsable de plusieurs projets. Chaque projet ne possède toutefois qu’un seul responsable. La relation de responsable entre la liste Team Members et la liste Projects est une relation un-à-plusieurs. Cette relation peut être représentée par des membres EntitySet<TEntity> de la classe TeamMember et un membre EntityRef<TEntity> de la classe Projects, comme illustré dans le code ci-après.

[ContentType(Name = "TeamMember")]
public class TeamMember
{
    private EntitySet<Project> projectsLedBy;

    [Association(List="Projects", MultivalueType=AssociationType.Multi)]
    public EntitySet<Project> ProjectsLedBy
    {
        get { return this.projectsLedBy; }
        set { this.projectsLedBy.Assign(value); }
    }

    // Declarations of other members suppressed for readability.
}

[ContentType(Name = "Project")]
public class Project
{
    [Column]
    public String Title { get; set; }

    private EntityRef<TeamMember> lead;

    [Association(List = "TeamMembers", MultiValueType = AssociationType.Single)]
    public TeamMember Lead
    {
        get { return this.lead.GetEntity(); }
        set { this.lead.SetEntity(value); }
    }

    // Declarations of other members suppressed for readability.
}

Listes de recherche avec plusieurs valeurs autorisées

La classe LookupList<T> représente les valeurs actuelles d’un champ de recherche qui autorise plusieurs valeurs. Il s’agit donc d’un sous-ensemble des valeurs de la colonne cible de la liste cible d’une relation de liste de recherche. Une classe de type de contenu peut avoir un champ privé de type LookupList<T> pour contenir les valeurs recherchées de la colonne dans l’objet d’élément de liste actuel.

Un champ de ce type n’est pas nécessaire, car vous pouvez utiliser une propriété EntitySet<TEntity> pour représenter une colonne de recherche. Vous souhaiterez peut-être avoir toutefois un champ de ce type en raison des différences de chargement entre LookupList<T> et EntitySet<TEntity>. Imaginons deux classes de type de contenu, A et B, qui sont identiques, excepté que A utilise un champ LookupList<T> pour représenter une colonne de recherche et B, EntitySet<TEntity>. Dans les deux cas, lorsque la requête est énumérée (en règle générale dans une boucle foreach) et plus particulièrement lorsque la boucle atteint un élément de liste spécifique du type de contenu, elle effectue une requête sur la base de données pour remplir les propriétés de l’objet représentant l’élément de liste. Pour un objet de type A, le champ LookupList<T> est immédiatement rempli avec les valeurs de la colonne de recherche. Les références ultérieures à ce champ (ou à une propriété qui l’enveloppe) dans la boucle foreach ne requièrent pas une seconde requête sur la base de données. Le chargement est toutefois différé pour les objets de type EntitySet<TEntity>. Lorsqu’une boucle foreach atteint donc un objet spécifique de type B, la propriété EntitySet<TEntity>*n’*est pas immédiatement remplie avec les éléments de la liste cible. Le chargement est différé jusqu’à ce que la propriété soit référencée pour la première fois dans le corps de la boucle. Lorsque cette référence à lieu, une seconde requête sur la base de données est requise pour remplir la propriété.

La section Jeux d’entités contient le code ci-après qui fournit un exemple d’appel à une propriété EntitySet<TEntity>. Dans cet exemple, le champ AssignedProjects de la liste Team Members est configuré en tant que champ de recherche du champ Title de la liste Projects. Il est également configuré pour autoriser plusieurs valeurs.

Project fiscalPlan = new Project() { Title="Fiscal year planning." };

TeamSite teamData = new TeamSite("http://DeptServer/TeamSite");

var filteredTeamMembers = from member in teamData.TeamMembers
                          where member.AssignedProjects.Contains(fiscalPlan) 
                          select member;

Comme EntitySet<TEntity> utilise un chargement différé, la valeur de la propriété TeamMember.AssignedProjects doit être obtenue de la base de données de contenu chaque fois qu’elle est référencée. Un objet LookupList<T> étant immédiatement chargé, du code qui appelle une propriété IList<T> enveloppant un champ LookupList<T> est donc plus performant que du code qui appelle la propriété EntitySet<TEntity>.

Pour continuer l’exemple, supposons que la classe TeamMember déclare un champ privatede type LookupList<T> (où T représente String) qui représente les valeurs du champ AssignedProjects provenant de la colonne cible de recherche (Title) de la liste Projects. Par convention, ce champ privé se voit attribuer un nom composé par une concaténation (casse mixte) du nom de la colonne de recherche et d’une version au pluriel de la colonne cible dont sont récupérées les valeurs. Dans ce cas, le champ porte le nom assignedProjectsTitles. Le champ est enveloppé par une propriété publique de type IList<String>. Par convention, le nom qu’elle se voit attribuer est une version en majuscules du nom du champ, à savoir AssignedProjectsTitles.

Notes

Les noms de la propriété IList<T> et du champ LookupList<T> sont au pluriel, car le champ de recherche autorise plusieurs valeurs. La classe LookupList<T> ne joue aucun rôle dans la représentation des champs de recherche qui autorisent uniquement une seule valeur.

La relation de la classe TeamMember avec la liste Projects est à présent déclarée, et la classe possède une propriété AssignedProjectsTitles pour référencer les valeurs du champ d’élément de liste Assigned Projects. Elle a besoin maintenant de quelque chose pour raccrocher les deux. Cela est réalisé en décorant la propriété AssignedProjectsTitles avec un attribut ColumnAttribute. Quatre propriétés de l’attribut sont définies :

  • Name="Assigned Projects" : spécifie la colonne dont les valeurs sont représentées par la propriété AssignedProjectsTitles.

  • FieldType="Lookup"  : spécifie que le champ identifié par la propriété Name doit être du type recherche dans SharePoint Foundation.

  • IsLookupValue=true : spécifie que le champ est un champ de recherche.

  • LookupDisplayColumn="Title" : spécifie la colonne cible de la liste cible.

Le code ci-après illustre les déclarations nécessaires à la prise en charge de la relation de recherche avec une propriété EntitySet<TEntity> et une propriété IList<T> qui enveloppe un champ LookupList<T>.

[ContentType(Name = "TeamMember")]
public class TeamMember
{
    [Column]
    public Int32 MemberID { get; set; }

    private EntitySet<Project> assignedProjects;

    private LookupList<String> assignedProjectsTitles;

    [Association(List="Projects", MultiValueType=Multi)]
    public EntitySet<Project> AssignedProjects
    {
        get { return this.assignedProjects; }
        set { this.assignedProjects.Assign(value); }
    }

    [Column Name="Assigned Projects", FieldType="Lookup", IsLookupValue="true", LookupDisplayColumn="Title"]
    public IList<String> AssignedProjectsTitles 
    {
        get { return this.assignedProjectsTitles; }
        set { this.assignedProjectsTitles.Assign(value); }
    }

    // Declarations of other members suppressed for readability.
}

[ContentType(Name = "Project")]
public class Project
{
    [Column]
    public String Title { get; set; }

    // Declarations of other members suppressed for readability.
}

Lorsque ces déclarations sont mises en place, il est possible d’obtenir une version plus performante de la requête précédente, comme illustré dans l’exemple ci-après.

TeamSite teamData = new TeamSite("http://DeptServer/TeamSite");

var filteredTeamMembers = from member in teamData.TeamMembers
                          where member.AssignedProjectsTitles.Contains("Fiscal year planning.") 
                          select member;

Notes

SPMetal génère un LookupList<T> uniquement lorsqu’une colonne de recherche pointe vers une liste cible qui n’est pas représentée par le code généré par SPMetal, comme une liste cible masquée ou exclue de la génération de code par le fichier de configuration de SPMetal. Pour plus d’informations, voir Remplacement des valeurs SPMetal par défaut par un fichier XML de paramètres.

Objets de listes de recherche d’ID spéciaux

Une fois définie, la valeur d’un champ de type Recherche se présente sous la forme ID;n°valeur_affichage, où valeur_affichage représente la valeur récupérée de la colonne cible de la liste cible et ID, l’ID de l’élément de liste de la liste cible dont la valeur a été sélectionnée. Il est supprimé dans l’interface utilisateur de SharePoint Foundation. Souvent, lorsqu’il existe une relation de recherche entre des listes et que la colonne de recherche autorise plusieurs valeurs, votre solution doit accéder aux ID des éléments de la liste cible dont les valeurs de la colonne cible sont celles de la colonne de recherche. Vous pouvez référencer ces valeurs par le biais de la propriété EntitySet<TEntity> représentant les éléments de la liste cible. Toutefois, dans ce cas aussi, le code s’exécute plus rapidement si ces ID sont stockés dans un champ LookupList<T>. Pour cette raison, il est conseillé d’avoir un champ de ce type et une propriété IList<T> publique pour l’envelopper, dès que vous avez un champ LookupList<T> pour contenir les valeurs recherchées.

La convention d’affectation de noms pour ces ID et propriétés spéciaux est la même que celle pour le champ et la propriété qui contiennent les valeurs recherchées, excepté que la deuxième partie de chaque nom est « Ids » au lieu d’une version au pluriel du nom de la colonne cible. L’attribut [Column] sur la propriété IList<T> est également le même.

L’exemple ci-après illustre les déclarations de Team Members et Projects étendues pour ajouter un champ LookupList<T> d’« ID » et sa propriété correspondante.

[ContentType(Name = "TeamMember")]
public class TeamMember
{
    [Column]
    public Int32 MemberID { get; set; }

    private EntitySet<Project> assignedProjects;

    private LookupList<String> assignedProjectsTitles; 

    private LookupList<String> assignedProjectsIds; 


    [Association(List="Projects", MultiValueType=Multi)]
    public EntitySet<Project> AssignedProjects
    {
        get { return this.assignedProjects; }
        set { this.assignedProjects.Assign(value); }
    }

    [Column Name="Assigned Projects", FieldType="Lookup", IsLookupValue="true", LookupDisplayColumn="Title"]
    public IList<String> AssignedProjectsTitles 
    {
        get { return this.assignedProjectsTitles; }
        set { this.assignedProjectsTitles.Assign(value); }
    }

    [Column Name="Assigned Projects", FieldType="Lookup", IsLookupValue="true"]
    public IList<String> AssignedProjectsIds 
    {
        get { return this.assignedProjectsIds; }
        set { this.assignedProjectsIds.Assign(value); }
    }    

    // Declarations of other members suppressed for readability.
}

[ContentType(Name = "Project")]
public class Project
{
    [Column]
    public String Title { get; set; }

    // Declarations of other members suppressed for readability.
}

Listes de recherche n’autorisant qu’une seule valeur

Un champ de recherche à valeur unique représente une relation un-à-un simple. Le champ privé stockant la valeur n’est donc que le type du champ cible et non le type LookupList<T>. De même, la propriété publique qui enveloppe le champ est du même type et non du type IList. (À proprement parler, le type du champ et de la propriété est l’équivalent Microsoft .NET Framework du type SharePoint Foundation du champ cible, comme expliqué dans Mappage des types : depuis le fournisseur LINQ to SharePoint vers .NET.) De plus, comme il n’y a qu’une seule valeur, les noms du champ et de la propriété ne sont pas au pluriel.

Imaginons une variation de l’exemple de la section précédente. Supposons que chaque membre d’équipe se voit affecter un seul projet et que l’affectation est enregistrée dans une colonne Project étant un champ de recherche de la colonne Title de la liste Projects. En plus d’utiliser un champ EntityRef<TEntity> pour représenter la relation entre les deux listes, la classe TeamMember déclarerait également un champ String privé appelé projectTitle et une classe String publique pour l’envelopper, appelée ProjectTitle. Bien que les noms du champ et de la propriété soient au singulier, notez qu’ils suivent la convention d’affectation de noms pour un valeur de recherche avec la concaténation du nom du champ de recherche et du nom du champ cible.

[ContentType(Name = "TeamMember")]
public class TeamMember
{
    private EntityRef<Project> project;

    private String projectTitle;

    [Association(List="Projects", MultiValueType=AssociationType.Single)]
    public Project Project
    {
        get { return this.project.GetEntity(); }
        set { this.project.SetEntity(value); }
    }

    [Column Name="Project", FieldType="Lookup", IsLookupValue="true", LookupDisplayColumn="Title"]
    public String ProjectTitle 
    {
        get { return this.projectTitle.GetEntity(); }
        set { this.projectTitle.SetEntity(value); }
   }

    // Declarations of other members suppressed for readability.
}

[ContentType(Name = "Project")]
public class Project
{
    [Column]
    public String Title { get; set; }

    // Declarations of other members suppressed for readability.
}

Notes

Dans le cas spécial où le champ de recherche effectue la recherche d’une valeur dans un autre champ de la même table, il n’existe aucune relation entre les tables. Pour cette raison, les déclarations du champ EntityRef<TEntity> et de la propriété qui l’enveloppe n’existeraient pas.

Recherches inversées

Vous pouvez déclarer une relation de liste dans les deux classes de type de contenu pour être en mesure d’effectuer des recherches inversées. Lorsque vous procédez ainsi et que la relation est une relation plusieurs-à-plusieurs, la propriété EntitySet<TEntity> de la liste cible possède un AssociationAttribute légèrement différent. Plus particulièrement, la propriété MultivalueType est définie sur AssociationType.Backward au lieu de Multi. La propriété Name est également définie sur le nom interne de la colonne de recherche source, c'est-à-dire, la cible d’une recherche inversée.

Voir aussi

Tâches

Procédure : utiliser SPMetal

Référence

SPMetal

Concepts

Suivi des modifications d’objets et accès concurrentiel optimiste