c# - exam ref 70-486 developing asp.net mvc web applications




Entity Framework 4-AddObject vs Attach (3)

J'ai récemment travaillé avec Entity Framework 4, et je suis un peu confus quant à savoir quand utiliser ObjectSet.Attach et ObjectSet.AddObject .

De ma compréhension:

  • Utilisez "Attacher" lorsqu'une entité existe déjà dans le système
  • Utilisez "AddObject" lors de la création d'une nouvelle Entité

Donc, si je crée une nouvelle personne , je le fais.

var ctx = new MyEntities();
var newPerson = new Person { Name = "Joe Bloggs" };
ctx.Persons.AddObject(newPerson);
ctx.SaveChanges();

Si je modifie une personne existante , je fais ceci:

var ctx = new MyEntities();
var existingPerson = ctx.Persons.SingleOrDefault(p => p.Name = "Joe Bloggs" };
existingPerson.Name = "Joe Briggs";
ctx.SaveChanges();

Gardez à l'esprit, c'est un exemple très simple . En réalité, j'utilise Pure POCO (pas de génération de code), le modèle Repository (ne pas traiter avec ctx.Persons), et Unit of Work (ne pas traiter avec ctx.SaveChanges). Mais "sous les couvertures", ce qui précède est ce qui se passe dans ma mise en œuvre.

Maintenant, ma question - je n'ai pas encore trouvé un scénario où j'ai dû utiliser Attach .

Qu'est-ce que j'oublie ici? Quand devons-nous utiliser Attach?

MODIFIER

Juste pour clarifier, je cherche des exemples de quand utiliser Attach sur AddObject (ou vice-versa).

EDIT 2

La réponse ci-dessous est correcte (que j'ai acceptée), mais j'ai pensé ajouter un autre exemple où Attach serait utile.

Dans mon exemple ci-dessus pour modifier une personne existante , deux requêtes sont en cours d'exécution.

Un pour récupérer la personne (.SingleOrDefault), et un autre pour effectuer la mise à jour (.SaveChanges).

Si (pour une raison quelconque), je savais déjà que "Joe Bloggs" existait dans le système, pourquoi faire une requête supplémentaire pour l'obtenir en premier? Je pourrais faire ceci:

var ctx = new MyEntities();
var existingPerson = new Person { Name = "Joe Bloggs" };
ctx.Persons.Attach(existingPerson);
ctx.SaveChanges();

Cela entraînera juste une instruction UPDATE en cours d'exécution.


C'est une réponse tardive mais cela pourrait aider d'autres personnes à trouver cela.

Fondamentalement, une entité "déconnectée" peut se produire lorsque vous manipulez une entité en dehors de la portée "using".

Employee e = null;

using (var ctx = new MyModelContainer())
{
     e = ctx.Employees.SingleOrDefault(emp => emp .....);
}

using (var ctx2 = new MyModelContainer())
{
     e; // This entity instance is disconnected from ctx2
}

Si vous entrez une autre portée "using" alors la variable "e" sera déconnectée car elle appartient à la portée "using" précédente et puisque la portée "using" précédente est détruite, alors "e" est déconnecté.

C'est comme ça que je le comprends.


Ceci est une citation de Programming Entity Framework: DbContext

Appeler Supprimer sur une entité qui n'est pas suivie par le contexte provoquera le lancement d'une exception InvalidOperationException. Entity Framework lève cette exception car il n'est pas clair si l'entité que vous essayez de supprimer est une entité existante qui doit être marquée pour la suppression ou une nouvelle entité qui doit simplement être ignorée. Pour cette raison, nous ne pouvons pas utiliser simplement Supprimer pour marquer une entité déconnectée comme Supprimée; Nous devons l'attacher en premier .

private static void TestDeleteDestination()
{
    Destination canyon;
    using (var context = new BreakAwayContext())
    {
        canyon = (from d in context.Destinations
        where d.Name == "Grand Canyon"
        select d).Single();
    }
    DeleteDestination(canyon);
}
private static void DeleteDestination(Destination destination)
{
    using (var context = new BreakAwayContext())
    {
        context.Destinations.Attach(destination);
        context.Destinations.Remove(destination);
        context.SaveChanges();
    }
}

La méthode TestDeleteDestination simule une application cliente qui récupère une destination existante à partir du serveur, puis la transmet à la méthode DeleteDestination sur le serveur. La méthode DeleteDestination utilise la méthode Attach pour indiquer au contexte qu'il s'agit d'une destination existante. Ensuite, la méthode Remove est utilisée pour enregistrer la destination existante pour la suppression


ObjectContext.AddObject et ObjectSet.AddObject :
La méthode AddObject permet d'ajouter des objets nouvellement créés qui n'existent pas dans la base de données. L'entité obtiendra un EntityKey temporaire généré automatiquement et son EntityState sera défini sur Ajouté . Lorsque SaveChanges est appelé, il sera clair pour l'EF que cette entité doit être insérée dans la base de données.

ObjectContext.Attach et ObjectSet.Attach :
D'un autre côté, Attacher est utilisé pour les entités qui existent déjà dans la base de données. Plutôt que de définir EntityState sur Added, Attacher des résultats dans un EntityState non modifié, ce qui signifie qu'il n'a pas changé depuis qu'il a été attaché au contexte. Les objets que vous attachez sont supposés exister dans la base de données. Si vous modifiez les objets après qu'ils ont été attachés, lorsque vous appelez SaveChanges, la valeur de EntityKey est utilisée pour mettre à jour (ou supprimer) la ligne appropriée en trouvant son ID correspondant dans la table db.

En outre, en utilisant la méthode Attach, vous pouvez définir des relations entre des entités qui existent déjà dans le ObjectContext mais qui n'ont pas été connectées automatiquement. Fondamentalement, le but principal de Attach, est de connecter les entités qui sont déjà attachées à ObjectContext et qui ne sont pas nouvelles, donc vous ne pouvez pas utiliser Attach pour attacher des entités dont EntityState est ajouté. Vous devez utiliser Add () dans ce cas.

Supposons par exemple que votre entité Person possède une propriété de navigation nommée Addresses, qui est une collection d'entités Address . Disons que vous avez lu les deux objets à partir du contexte, mais ils ne sont pas liés les uns aux autres et vous voulez le faire ainsi:

var existingPerson = ctx.Persons.SingleOrDefault(p => p.Name = "Joe Bloggs" };
var myAddress = ctx.Addresses.First(a => a.PersonID != existingPerson.PersonID);
existingPerson.Addresses.Attach(myAddress);
// OR:
myAddress.PersonReference.Attach(existingPerson)
ctx.SaveChanges();




crud