2009-05-04 5 views
0

J'ai une situation où une table de message a une clé primaire (Id) et une clé étrangère (Site). Tout site peut créer un enregistrement de message, mais seul le site qui a créé l'enregistrement peut le mettre à jour. Le problème est que, par défaut, il sera mis à jour en fonction de l'identifiant et non de l'identifiant et du site. Je pourrais changer la clef primaire pour être un composé/composé composé de l'id et du site OU recours au SQL natif; Cependant, je me demandais s'il y avait un moyen d'ajouter des critères de mise à jour supplémentaires.Comment ajouter des critères supplémentaires à ma commande de mise à jour en utilisant NHibernate?

Par exemple, voici ce que vous obtenez par défaut:

 
public void MessageUpdate(Message oneMessage) 
{ 
    using(ISession session = SessionFactory.OpenSession()) 
    using(ITransaction trans = session.BeginTransaction()) 
    { 
     session.Update(oneMessage); 
     trans.Commit(); 
    } 
} 

Alors, comment dois-je faire cela dans NHibernate sans créer un identifiant composé ou en utilisant SQL natif:

 
Update MessageTable set MessageStatus = 2 where Id = ? and Site = ?; 
+0

En note, vous n'avez pas besoin de session.Update dans votre code. Plus d'informations ici http://www.tobinharris.com/past/2009/6/11/nhibernate-calling-update-unnecessarily/ – autonomatt

Répondre

0

Je pense que la réponse courte à ma question initiale est que vous ne pouvez pas ajouter de critères à une mise à jour. Vous pouvez utiliser le SQL natif pour gérer cette situation comme suggéré initialement:

Mettre à jour MessageTable définir MessageStatus = 2 où Id =? et Site =?

Ou vous pourriez aborder le problème comme Jamie Ide suggéré, mais il faudra une requête supplémentaire contre la base de données pour tirer le message original.

0

Ce que je comprends de votre question, la règle est une exigence de l'entreprise, alors peut-être que NHibernate n'est pas l'endroit pour cette règle. Vous pouvez essayer d'implémenter un écouteur sur l'événement de mise à jour: http://nhibernate.info/blog/2009/04/29/nhibernate-ipreupdateeventlistener-amp-ipreinserteventlistener.html

Une autre solution consiste à marquer la propriété avec la mise à jour à false pour empêcher le changement du site de l'enregistrement? http://nhibernate.info/doc/nh/en/index.html#mapping-generated (voir propriété générée)

+0

La règle de sécurité serait: "Les utilisateurs ne peuvent pas mettre à jour les enregistrements de messages pour les sites qu'ils n'ont pas. accès à". Si une connexion utilisateur est compromise, l'attaquant ne peut que corrompre les messages associés à un site donné. Si je peux avoir des critères de mise à jour supplémentaires, je peux prendre l'identifiant et le statut de l'utilisateur et obtenir son identifiant de site depuis la base de données. Je peux ensuite créer une instruction de mise à jour en utilisant id, siteid et status. Ainsi, un utilisateur qui n'a pas accès à un site ne peut jamais gâcher les enregistrements d'un autre site. –

0

Vous ne pouvez pas le faire directement dans NHibernate mais vous pouvez modifier votre méthode de mise à jour:

public void MessageUpdate(Message oneMessage, string currentSite) 
{ 
    if (oneMessage.Site != currentSite) 
    { 
     throw new Exception("meaningful error message"); 
    } 
    using(ISession session = SessionFactory.OpenSession()) 
    using(ITransaction trans = session.BeginTransaction()) 
    { 
     session.Update(oneMessage); 
     trans.Commit(); 
    } 
} 

En supposant site est une chaîne et une propriété de message. Aussi, vous voudrez envelopper votre mise à jour dans un try..catch et annuler la transaction si une exception se produit.

+0

Le seul problème est que l'enregistrement est toujours mis à jour en fonction de l'ID, donc le site pourrait être faux et toujours mettre à jour le mauvais enregistrement. Le seul vrai moyen de vérifier le site consiste à interroger la base de données pour le message, vérifier l'ID du site, puis le comparer à l'ID du site auquel l'utilisateur est autorisé à accéder. Cela nécessiterait un voyage supplémentaire dans la base de données, que j'essayais d'éviter. L'identifiant composite résoudrait ce problème en exigeant que l'identifiant et l'identifiant du site soient utilisés. Actuellement, j'ai recouru au SQL natif pour résoudre ce problème, mais j'espérais pouvoir ajouter des critères supplémentaires à la mise à jour. –

+0

"afin que le site pourrait être faux et toujours mettre à jour le mauvais enregistrement." - Pas si vous effectuez des mises à jour en utilisant une méthode similaire à celle que j'ai écrite en exemple. Si une connexion est compromise, l'attaquant ne peut faire que ce que l'application permet. Si l'application ou le serveur est compromis pour qu'un attaquant puisse contourner cette méthode ou écrire son propre SQL alors la seule protection est la sauvegarde fréquente. –

+0

Jamie, merci pour votre réponse. Je suppose que la réponse courte à ma question initiale est que vous ne pouvez pas ajouter des critères à une mise à jour. Dans votre exemple, je devrais toujours interroger le message d'origine dans la base de données, mettre à jour le champ d'état, laisser l'ID de site seul, puis appeler votre méthode MessageUpdate avec le message et le site actuel auquel l'utilisateur a accès. Cela fonctionnera certainement, mais en utilisant SQL natif, je peux éviter la requête et utiliser une instruction where pour vérifier que l'ID du site de l'utilisateur correspond à l'ID du site dans l'enregistrement. Si aucun enregistrement n'est mis à jour, je peux effectuer diverses actions. –

Questions connexes