2009-08-08 8 views
0

J'ai deux tables dans ma base de données:Quelle est la manière la plus élégante d'implémenter une règle métier relative à une collection enfant dans LINQ?

Wiki 
    WikiId 
    ... 

WikiUser 
    WikiUserId (PK) 
    WikiId 
    UserId 
    IsOwner 
    ... 

Ces tableaux ont un (Wiki) à la relation Beaucoup (wikiuser).

Comment puis-je mettre en œuvre la règle métier suivante dans mes classes d'entités LINQ:

« Un wiki doit avoir exactement un propriétaire? »

J'ai essayé de mettre à jour les tables comme suit:

Wiki 
    WikiId (PK) 
    OwnerId (FK to WikiUser) 
    ... 

WikiUser 
    WikiUserId (PK) 
    WikiId 
    UserId 
    ... 

Ceci impose la contrainte, mais si je retire de la collection wikiuser du Wiki record wikiuser du propriétaire, je reçois un SqlException laid. Cela semble être difficile à attraper et à gérer dans l'interface utilisateur.

Existe-t-il un moyen d'effectuer cette vérification avant la génération de SqlException? Une meilleure façon de structurer ma base de données? Un moyen d'attraper et de traduire le SqlException à quelque chose de plus utile? Editer: Je préférerais conserver les règles de validation dans les classes d'entités LINQ si possible.

Édition 2: Quelques détails supplémentaires sur ma situation spécifique.

Dans mon application, l'utilisateur devrait pouvoir supprimer des utilisateurs du Wiki. Ils devraient être en mesure de supprimer tout utilisateur, sauf l'utilisateur qui est actuellement signalé comme le "propriétaire" du wiki (un Wiki doit avoir exactement un propriétaire à tout moment).

Dans ma logique de commande, je voudrais utiliser quelque chose comme ceci:

wiki.WikiUsers.Remove(wikiUser); 
mRepository.Save(); 

et ont des règles cassées transférées à la couche d'interface utilisateur.

Ce que je ne veux pas avoir à faire est la suivante:

if(wikiUser.WikiUserId != wiki.OwnerId) { 
    wiki.WikiUsers.Remove(wikiUser); 
    mRepository.Save(); 
} 
else { 
    //Handle errors. 
} 

Je ne veux également pas particulièrement de déplacer le code à mon dépôt (parce qu'il n'y a rien à indiquer de ne pas utiliser le natif Retirer les fonctions), donc je aussi ne veulent pas que le code comme ceci:

mRepository.RemoveWikiUser(wiki, wikiUser) 
mRepository.Save(); 

ce serait acceptable:

try { 
    wiki.WikiUsers.Remove(wikiUser); 
    mRepository.Save(); 
} 
catch(ValidationException ve) { 
    //Display ve.Message 
} 

Mais attrape trop d'erreurs:

try { 
    wiki.WikiUsers.Remove(wikiUser); 
    mRepository.Save(); 
} 
catch(SqlException se) { 
    //Display se.Message 
} 

Je préférerions également de ne pas appeler explicitement une vérification de règles métier (bien qu'il puisse être nécessaire):

wiki.WIkiUsers.Remove(wikiUser); 
if(wiki.CheckRules()) { 
    mRepository.Save(); 
} 
else { 
    //Display broken rules 
} 

Répondre

0

Cette question a trop de dépendances pour répondre bien-dont le plus grand est où vous prévoyez d'appliquer des règles d'affaires dans l'ensemble. Par ordre de préférence, vous devez demander: avez-vous une couche de règles métier? Si non, avez-vous une couche d'accès aux données indépendante? Si non, utilisez-vous un modèle de fournisseur de données?Si ce n'est pas le cas, alors vous cherchez à imposer ce genre de chose (ou à gérer l'exception SqlException) partout où vous manipulez l'interface de configuration.

Pour quelque chose comme un wiki, vous n'avez probablement pas besoin d'un moteur de règles métier extrêmement complexe simplement parce que votre domaine de problème est déjà très limité. En outre, cela semble être le genre de règle qui ne change pratiquement jamais alors l'isoler dans une couche de règles formelles est un peu exagéré. En tant que tel, vous êtes probablement mieux de mettre ce genre de contrainte dans la couche de données ou le fournisseur de données. Par exemple, si vous utilisez Linq to Sql, vous pouvez refléter ce que vous avez fait dans SQL Server en faisant de la propriété OwnerId de votre modèle une propriété non nullable liée par une relation à la table WikiUser. Cela ferait en sorte que la propriété OwnerId est remplie (car elle est non-nullable) et vous donnera la contrainte unique que vous recherchez.

+0

Ma préférence serait de faire la validation dans les objets LINQ. Avant d'aborder ce problème, j'avais prévu de m'appuyer sur OnValidate. – AaronSieb

+0

Le problème principal survient lorsque je supprime un WikiUser de la collection enfant du Wiki (en d'autres termes, lorsque je supprime un WikiUser). C'est à ce moment-là que je reçois l'exception SqlException, et je préfère recevoir quelque chose de plus ciblé. – AaronSieb

+0

Est-ce que cela arrive pour tous les utilisateurs ou seulement pour le propriétaire? Que voulez-vous arriver lorsque le propriétaire est supprimé? Est-ce que cette opération devrait être évitée ou devrait-on simplement mettre à zéro le OwnerId? –

Questions connexes