What is the most elegant way to implement a business rule relating to a child collection in LINQ?

Posted by AaronSieb on Stack Overflow See other posts from Stack Overflow or by AaronSieb
Published on 2009-08-08T00:00:35Z Indexed on 2010/04/16 18:03 UTC
Read the original article Hit count: 285

Filed under:
|
|

I have two tables in my database:

Wiki
    WikiId
    ...

WikiUser
    WikiUserId (PK)
    WikiId
    UserId
    IsOwner
    ...

These tables have a one (Wiki) to Many (WikiUser) relationship.

How would I implement the following business rule in my LINQ entity classes:

"A Wiki must have exactly one owner?"

I've tried updating the tables as follows:

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

WikiUser
    WikiUserId (PK)
    WikiId
    UserId
    ...

This enforces the constraint, but if I remove the owner's WikiUser record from the Wiki's WikiUser collection, I recieve an ugly SqlException. This seems like it would be difficult to catch and handle in the UI.

Is there a way to perform this check before the SqlException is generated? A better way to structure my database? A way to catch and translate the SqlException to something more useful?

Edit: I would prefer to keep the validation rules within the LINQ entity classes if possible.

Edit 2: Some more details about my specific situation.

In my application, the user should be able to remove users from the Wiki. They should be able to remove any user, except the user who is currently flagged as the "owner" of the Wiki (a Wiki must have exactly one owner at all times).

In my control logic, I'd like to use something like this:

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

And have any broken rules transferred to the UI layer.

What I DON'T want to have to do is this:

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

I also don't particularly want to move the code to my repository (because there is nothing to indicate not to use the native Remove functions), so I also DON'T want code like this:

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

This WOULD be acceptable:

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

But this catches too many errors:

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

I would also PREFER NOT to explicitly call a business rule check (although it may become necessary):

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

© Stack Overflow or respective owner

Related posts about LINQ

Related posts about .NET