Partager via


Procédure : écrire dans les bases de données de contenus en utilisant LINQ to SharePoint

Dernière modification : vendredi 24 juin 2011

S’applique à : SharePoint Foundation 2010

Dans cet article
Étapes 1 et 2 : obtention de références aux sites Web et aux listes
Étape 3 : vérifier que le suivi des modifications d’objet est activé
Étape 4 : ajout du code de base pour ajouter, supprimer, recycler ou mettre à jour un élément de liste
Étape 5 : ajouter l’infrastructure pour gérer les conflits d’accès concurrentiel

Cette rubrique explique comment écrire du code en utilisant le fournisseur LINQ to SharePoint pour ajouter ou supprimer des éléments de liste dans des listes Microsoft SharePoint Foundation et pour changer des valeurs de champs particuliers dans des éléments de liste.

Étapes 1 et 2 : obtention de références aux sites Web et aux listes

Pour savoir comment obtenir une référence dans votre code au site Web et à la liste dont vous souhaitez modifier des données, voir les étapes 1 et 2 de la rubrique Procédure : effectuer des requêtes à l’aide de LINQ to SharePoint.

Étape 3 : vérifier que le suivi des modifications d’objet est activé

La propriété ObjectTrackingEnableddoit être définie sur sa valeur par défaut true pour pouvoir utiliser LINQ to SharePoint afin d’apporter des modifications à la base de données. Si votre code définit cette propriété sur false et a demandé l’objet DataContext avec cette valeur en place, la propriété ne peut pas être rétablie à true. Par conséquent, si votre code interroge l’objet DataContext, puis effectue des changements dans la base de données de contenu, vous disposez de deux options :

  • Évitez que votre code définisse la propriété ObjectTrackingEnabled sur false.

  • Créez un nouvel objet DataContext pour le même site Web dans votre code, et situez-le après les requêtes mais avant que le code n’écrive dans la base de données. Laissez la propriété ObjectTrackingEnabled du nouvel objet DataContext sur sa valeur par défaut true et utilisez cet objet pour écrire dans la base de données de contenu.

Étape 4 : ajout du code de base pour ajouter, supprimer, recycler ou mettre à jour un élément de liste

Le code de base pour écrire dans les bases de données de contenu est simple. Vous commencez par créer une référence au site Web et à la liste et vous terminez par un appel à SubmitChanges(). Entre ces deux opérations, vous insérez le code effectuant les changements souhaités à l’aide de l’une des méthodes *OnSubmit de la classe EntitySet<TEntity> ou vous écrivez dans les champs de liste en utilisant la syntaxe ordinaire de définition de propriété. Dans tous les exemples suivants, teamSite est un objet DataContext qui représente un site Web et TeamMembers est un objet EntitySet<TEntity> qui représente une liste Membres d’équipe.

Important

L’objet qui représente l’élément de liste que vous ajoutez, supprimez, recyclez ou mettez à jour doit comporter des propriétés EntityState, Id et Version. C’est le cas si la classe représentant le type de contenu est générée par SPMetal. Les diverses méthodes *OnSubmit affectent des valeurs à la propriété EntityState. Les propriétés Id et Version sont définies par le runtime SharePoint Foundation. Votre code ne doit écrire dans aucune de ces propriétés.

Ajout d’un élément de liste

Pour ajouter un élément à une liste, créez un objet du type de contenu de la liste et passez-le à la méthode InsertOnSubmit(TEntity).

Important

Les propriétés de l’objet élément de liste qui représentent les champs requis du type de contenu doivent posséder une valeur avant l’insertion de l’élément dans la liste (ces mêmes propriétés sont déclarées avec une décoration [ColumnAttribute] dont la propriété Required existe et est définie sur true). Par exemple, tous les types de contenu héritent du type de contenu Élément de base de SharePoint Foundation qui a un champ Titre requis. Vous pouvez affecter des valeurs à ces propriétés entre l’appel de InsertOnSubmit(TEntity) et l’appel de SubmitChanges() ; mais, il est recommandé d’initialiser les propriétés requises dès que possible. S’il n’y a pas de de constructeur de classe qui initialise toutes les propriétés requises, vous pouvez utiliser un initialiseur d’objet comme indiqué dans l’exemple ci-dessous.

L’exemple suivant montre comment ajouter un élément à une liste, puis enregistrer les modifications dans la base de données.

// Create the new list item.
TeamMember bob = new TeamMember() { Title="Bob Smith" };

// Set the item to be inserted.
teamSite.TeamMembers.InsertOnSubmit(bob);

// Write changes to the content database.
teamSite.SubmitChanges();

Il existe également une méthode InsertAllOnSubmit(IEnumerable<TEntity>) qui vous permet d’insérer plusieurs éléments.

Suppression et recyclage d’un élément de liste

L’exemple suivant montre comment utiliser la méthode DeleteOnSubmit(TEntity) pour supprimer un élément d’une liste.

// Set the item to be deleted.
foreach (TeamMember teamMember in teamSite.TeamMembers)
{
    if (teamMember.Title = "Bob Smith")
    {
        teamSite.TeamMembers.DeleteOnSubmit(teamMember);
    }
}

// Write changes to the content database.
teamSite.SubmitChanges();

Pour placer un élément dans la Corbeille de l’utilisateur au lieu de le supprimer définitivement, utilisez la méthode RecycleOnSubmit(TEntity). Vous pouvez également utiliser les méthodes DeleteAllOnSubmit(IEnumerable<TEntity>) et RecycleAllOnSubmit(IEnumerable<TEntity>) pour supprimer plusieurs éléments en même temps.

Modification d’un champ dans un élément de liste

Pour changer la valeur d’un champ dans un élément de liste, écrivez simplement dans la propriété qui représente ce champ, comme illustré dans l’exemple suivant :

// Set the property to a new value.
foreach (TeamMember teamMember in teamSite.TeamMembers)
{
    teamMember.TopTask = "Fiscal Planning";
}

// Write changes to the content database.
teamSite.SubmitChanges();

Changements multiples avec un seul appel à SubmitChanges

Le nombre de changements que votre code peut effectuer avec un appel de la méthode SubmitChanges() n’est pas limité. Pour de meilleures performances, votre code doit minimiser le nombre d’appels autant que possible. Le code suivant illustre plusieurs types de changements enregistrés dans la base de données de contenu avec un seul appel à SubmitChanges() :

// ‘sally’ is a TeamMember object.
teamSite.TeamMembers.RecycleOnSubmit(sally);

// ‘leftCompany’ is an IList of TeamMember objects
teamSite.TeamMembers.DeleteAllOnSubmit(leftCompany);

foreach (TeamMember teamMember in teamSite.TeamMembers)
{
    teamMember.TopTask = "Fiscal Planning";
}

// Write changes to the content database.
teamSite.SubmitChanges();

Les changements que vous soumettez ne doivent pas nécessairement porter sur la même liste. Des changements sur plusieurs listes (voire toutes) dans un site Web peuvent être soumis avec un seul appel à SubmitChanges().

Étape 5 : ajouter l’infrastructure pour gérer les conflits d’accès concurrentiel

Si vous avez modifié des valeurs de champs, avant de soumettre ces changements à la base de données de contenu par un appel de la méthode SubmitChanges(), le système de suivi des modifications d’objet vérifie si un autre utilisateur a modifié l’un quelconque des éléments de liste affectés après la récupération de ceux-ci dans la base de données par l’utilisateur actuel (pour plus d’informations sur ce système, voir Suivi des modifications d’objets et accès concurrentiel optimiste). S’il y a conflit d’accès concurrentiel, SubmitChanges() génère une exception ChangeConflictException. En outre, un objet MemberChangeConflict représentant les informations sur l’incohérence est généré. S’il existe d’autres incohérences entre la valeur cliente actuelle d’un champ et la valeur de ce champ dans la base de données, chacune est représentée par un objet MemberChangeConflict. Toutes les incohérences pour un élément de liste spécifié sont ajoutées à la propriété MemberConflicts d’un objet ObjectChangeConflict. En fonction de la surcharge de SubmitChanges() ayant été appelée et des paramètres qui lui ont été passés, il peut exister plusieurs objets ObjectChangeConflict. Ils sont tous ajoutés à la propriété ChangeConflicts de l’objet DataContext.

Votre code doit intercepter l’exception et résoudre toutes les incohérences avant d’appeler à nouveau SubmitChanges(). Dans certains cas, la meilleure façon de traiter les problèmes est d’inviter l’utilisateur à décider comment résoudre chaque incohérence rencontrée. Vous pouvez remplir l’interface que vous présentez à l’utilisateur avec les données des objets ObjectChangeConflict de la propriété ChangeConflicts et les données de leurs objets MemberChangeConflict enfants, notamment les propriétés OriginalValue, DatabaseValue et CurrentValue.

ConseilConseil

Pensez à distinguer clairement dans votre interface utilisateur les incohérences qui représentent de réels conflits d’accès concurrentiel (incohérences entre les propriétés OriginalValue et DatabaseValue) de celles qui représentent simplement des modifications qui auraient été automatiquement enregistrées dans la base de données de contenu si aucun conflit d’accès concurrentiel n’avait eu lieu (incohérences entre DatabaseValue et CurrentValueOriginalValue = DatabaseValue).

Implémentez les choix de l’utilisateur par des appels à une combinaison des méthodes suivantes :

Dans d’autres cas, vous connaissez au moment du codage la meilleure façon de résoudre les incohérences, en fonction du but de votre application et du type des changements qu’elle effectue dans les bases de données de contenu. Dans de tels cas, il peut s’avérer préférable d’appeler une combinaison des méthodes de la liste précédente sans invite à l’utilisateur. Vous devez considérer les quatre points essentiels suivants pour construire votre logique de résolution :

  • Quelle version de valeur d’un champ doit être conservée dans la base de données de contenu, la valeur d’origine, la valeur actuellement en base de données, la valeur dans le traitement de votre application (la valeur cliente) ou une autre valeur ? Pour de l’aide, voir RefreshMode et les rubriques de référence des méthodes de la liste précédente. Par ailleurs, bien que les articles répertoriés dans le tableau suivant traitent du fournisseur LINQ to SQL, la logique qu’ils décrivent s’applique également à LINQ to SharePoint.

    Procédure : résoudre les conflits d’accès concurrentiel en fusionnant des valeurs de base de données (LINQ to SQL)

    Procédure : résoudre des conflits d’accès concurrentiel en conservant des valeurs de base de données (LINQ to SQL)

    Procédure : résoudre des conflits d’accès concurrentiel en remplaçant des valeurs de base de données (LINQ to SQL)

  • Que souhaitez-vous faire lorsque l’utilisateur actuel a soumis une modification d’un élément de liste qu’un autre utilisateur a supprimé totalement de la liste ? Pour plus d’informations à propos de ces options, voir Resolve(RefreshMode, Boolean) et ResolveAll(RefreshMode, Boolean).

  • À quel niveau devez-vous appliquer vos décisions dans les deux scénarios précédents ? Supposez, par exemple, que vous vouliez appliquer les règles suivantes à chaque incohérence pour chaque élément de liste de chaque liste :

    • Ignorer les éléments de liste qui ont été supprimés par un autre utilisateur.

    • Conserver tous les changements apportés par le traitement de votre application ainsi que ceux des processus d’autres utilisateurs, avec préférence pour vos propres changements lorsqu’ils sont en conflit avec ceux d’autres utilisateurs.

    Vous pouvez appliquer cette logique par un simple appel à ChangeConflictCollection.ResolveAll().

    Mais si vous souhaitez conserver tous les changements sur les éléments de certaines listes, tout en annulant les changements de votre propre traitement sur des éléments d’autres listes, alors votre code doit parcourir les membres de la propriété ChangeConflicts en appelant différentes surcharges de ObjectChangeConflict.Resolve() et en passant différents paramètres pour les différents éléments ObjectChangeConflict.

    Pour certains types de contenu, vous devrez peut-être appliquer différentes règles pour différents champs. Dans ce cas, votre code doit parcourir les membres de la propriété MemberConflicts de certains objets ObjectChangeConflict et appeler différentes surcharges de MemberChangeConflict.Resolve() en passant différents paramètres pour différents champs.

  • Quand souhaitez-vous générer une exception ChangeConflictException et arrêter d’apporter des changements supplémentaires ? Cela fait partie de votre logique de résolution, bien que vous implémentiez votre décision par l’appel à SubmitChanges(). Vous disposez de deux options : générer l’exception immédiatement en cas de conflit d’accès concurrentiel ou continuer à écrire tous les changements en attente. Dans ce dernier cas, l’exception est générée (et les changements sur les champs où il y a conflit sont annulés) si un ou plusieurs conflits sont détectés. Un avantage de la seconde option est que la propriété MemberConflicts contient les détails complets de tous les conflits d’accès concurrentiel (et des autres incohérences) pour le jeu entier des changements soumis. Par conséquent, votre logique de résolution peut gérer le jeu entier. Vous déterminez l’option à prendre par la surcharge SubmitChanges() appelée et par les paramètres que vous passez à celle-ci.

L’exemple de code suivant illustre la façon la plus simple de résoudre toutes les incohérences.

foreach (TeamMember teamMember in teamSite.TeamMembers)
{
    teamMember.TopTask = "Fiscal Planning";
}

try 
{
    teamSite.SubmitChanges();
}
catch (ChangeConflictException e) 
{
    teamSite.ChangeConflicts.ResolveAll();
    teamSite.SubmitChanges();
}

Le premier appel à SubmitChanges() est la surcharge sans paramètre. Elle génère une exception dès le premier conflit d’accès concurrentiel détecté. Par conséquent, l’appel de ChangeConflictCollection.ResolveAll() résout uniquement toutes les incohérences enregistrées jusque-là. Si un autre conflit est inclus dans les changements soumis, le second appel de SubmitChanges() génère une exception.

Le code suivant est un exemple plus complexe de résolution des incohérences.

foreach (TeamMember teamMember in teamSite.TeamMembers)
{
    teamMember.TopTask = "Fiscal Planning";
}

try 
{
    teamSite.SubmitChanges(ConflictMode.ContinueOnConflict);
}
catch (ChangeConflictException e) 
{
    foreach (ObjectChangeConflict changedListItem in teamSite.ChangeConflicts)
    {
        // If another user has changed properties of a non-manager,
        // leave that other user’s changes, except for the TopTask field.
        if (((TeamMember)changedListItem.Object).IsManager = false)
        {        
             foreach (MemberChangeConflict changedField in changedListItem.MemberConflicts)
            {
                if (changedField.Member.Name == "TopTask")
                {
                    changedField.Resolve(RefreshMode.KeepCurrentValues);
                }
                else
                {
                    changedField.Resolve(RefreshMode.OverwriteCurrentValues);
                }
            }
        }
        // But if another user has changed properties of a manager, let this
        // process’s changes override the other user’s changes.
        else
        {
            changedListItem.Resolve(RefreshMode.KeepCurrentValues);
        }    
    }

    teamSite.SubmitChanges();
} // end catch