2011-02-11 2 views
1

J'ai donc deux tables dans ma base de données, contacts et adresses:Les meilleures pratiques pour l'insertion/mise à jour des données dans plusieurs tables à la fois

Contacts: ContactID | AddressID | Prénom | Nom

Adresses: AddressID | Adresse1 | Adresse2 | Ville | Etat | Code postal

J'ai une page où vous pouvez ajouter un contact. Il contient toutes les informations pour un contact et une adresse pour un contact. Voici mon code lorsque vous soumettez le formulaire:

[HttpPost] 
public ActionResult Edit(ContactsViewModel viewModel) 
{ 
    //if editing an contact, fetch it; otherwise, create a new one 
    Contact contact = viewModel.ContactId == 0 
     ? new Contact() 
     : _adminRepository.GetContact(viewModel.ContactId); 
    TryUpdateModel(contact); 

    if (ModelState.IsValid) 
    { 
     _adminRepository.SaveAddress(contact.Address); 
     _adminRepository.SaveContact(contact); 

     return RedirectToAction("Index"); 
    } 
    return View(viewModel);  // validation error, so redisplay same view 
} 

Maintenant, ma principale préoccupation est que l'adresse est ajoutée avec succès, mais alors une erreur se produit lorsque je tente d'enregistrer le contact, laissant l'adresse dans la base de données sans contact.

Quelle est la meilleure pratique pour annuler les modifications en cas d'erreur?

+0

Que faites-vous dans SaveAddress et SaveContact? essayez-vous de vous engager dans DB? essayez d'utiliser Unit of Work –

Répondre

0

Vous devez utiliser TransactionScope() dans votre référentiel. Découvrez MSDN forum entry. La première réponse montre un exemple simple pour l'intégrer dans une méthode. La clé est que, sans cela, il n'y a pas moyen d'annuler spécifiquement les changements.

4

Eh bien cela devrait être une méthode, pas deux.

Si un Adresse est toujours liée à un contact (il semble de cette façon), alors vous ne devriez avoir un dépôt - un ContactRepository par exemple.

Vous devez avoir un référentiel par racine agrégée, ou en termes simples - un référentiel pour chaque entité qui doit être récupérée par elle-même.

Je ne sais pas ce qu'est _adminRepository, mais je pense que vous avez juste une méthode SaveContact(contact).

Utilisez-vous un ORM comme Entity Framework? Si c'est le cas, les deux insertions seront effectuées en une seule transaction (gérée par EF), donc si l'une échoue, les deux vont échouer.

Si vous commencez à faire des changements contre plusieurs référentiels/racines globales, alors vous aurez besoin de quelque chose comme une unité de travail , ou un TransactionScope.

Il semble donc que vous ayez besoin de repenser un peu la conception de votre référentiel. Il devrait y avoir une méthode générique Save pour une entité agrégée unique (Contact), et non des entités séparées pour chaque relation.

+0

Oui, j'utilise Entity Framework. Mon référentiel admin contient des fonctions pour chaque entité, donc il y a SaveContact(), SaveAddress, GetAllContacts(), GetAllAddresses(), etc. Est-ce que je fais ça correctement? – Steven

+0

@Steven - deux questions: 1) Pouvez-vous ajouter une adresse sans contact? 2) Pouvez-vous ajouter un contact sans adresse? On dirait que la réponse est non et non. Est-ce exact? – RPM1984

+0

C'est en fait oui et non :). Vous pouvez ajouter une adresse sans contact, mais vous devez ajouter un contact avec une adresse. – Steven

0

Ma préférence serait de faire une seule procédure stockée pour insérer les deux dossiers. Vous pouvez utiliser des transactions TSQL. L'utilisation d'un TransactionScope() fonctionnerait également, donc la décision devrait probablement être basée sur votre couche d'accès aux données. Si vous utilisez déjà beaucoup de SPROC, faites-en un complexe avec une transaction.

Si vous utilisez Entity Framework (... la douleur !!!!) alors un .net TransactionScope() serait mieux.

Questions connexes