2009-09-15 5 views
2

Mise à jour applications Ajouté ci-dessousLes associations ont unidirectionnels mènent à des champs clés étrangers non requis par NHibernate

résumé Question J'ai une base de données avec de nombreux domaines clés étrangères nécessaires et une base de code avec de nombreuses associations unidirectionnelles . Je veux utiliser NHibernate, mais pour autant que je sache, je dois soit rendre les champs de clé étrangers dans la base de données NULLable (pas une option réaliste) ou changer les associations en bidirectionnel (pas idéal non plus). D'autres options que j'ai ratées?

Fond J'ai rejoint un projet qui utilise NHibernate pour cartographier les tables 1: 1 à objets dits « techniques ». Après la récupération des données, les objets sont mappés au modèle de domaine réel (style AutoMapper, implémenté différemment). Je sais que c'est une étape inutile et je veux proposer de le retirer à l'équipe. Cependant, je suis confronté à un problème.

Le modèle de domaine contient de nombreuses associations unidirectionnelles: l'objet Case possède une liste de personnes associées à l'observation, mais les personnes ne contiennent pas de référence à l'objet Case. Dans le schéma de base de données sous-jacent, la table Person possède un champ de clé étrangère obligatoire qui fait référence à l'ID de requête. Le modèle de données:

[ERD] 
       PERSON 
CASE   Id*   Ids are generated by the DB 
Id* <--FK-- CaseId*  * denotes required fields 
(other)  (other)   

Le modèle de domaine ressemble à ceci:

public class Person : DomainEntity 
{ // DomainEntity implements Id. Non-essential members left out } 

public class Case : DomainEntity 
{ 
    public virtual IList<Person> Persons { get; set; } 
} 

Appel session.Save() sur un cas conduit à une erreur de base de données (CASEID requise lors de l'insertion dans la personne), parce que NHibernate commence par l'insertion des entrées Person, suivie de l'entrée Case et se termine par la mise à jour de la colonne CaseId dans les entrées Person. Si la colonne CaseId de la base de données est modifiée à non requise (autoriser les valeurs NULL), tout fonctionne comme il se doit ... cependant, ce changement n'est pas une option pour le moment (le modèle de base de données est partagé par plusieurs applications an). La seule façon que j'ai trouvé pour obtenir NHibernate pour exécuter les actions de base de données est correctement en changeant l'association bidirectionnelle, à savoir, en changeant Personne à

public class Person : DomainEntity 
{ 
    public virtual Case Case { get; set; } 
} 

Cela implique des changements importants à la base de code existante cependant, je préférerait des alternatives, si elles existent. J'ai joué avec les mappages de composants, mais c'est un mauvais choix car la plupart des associations dans notre modèle ne sont pas des compositions réelles (UML). Y a-t-il d'autres options que j'ai ratées? TIA!

EDIT Le (courant) pour la cartographie de cas ressemble à ceci:

public class CaseMapping : ClassMap<Case> 
{ 
    public CaseMapping() 
    { 
     Not.LazyLoad(); 

     Id(c => c.Id).GeneratedBy.Identity(); 
     Map(x => x.Code).Not.Nullable().Length(20); 
     Map(x => x.Name).Not.Nullable().Length(100); 
     HasMany<Person>(x => x.Persons) 
      .AsBag() 
      .KeyColumn("CaseId") 
      .ForeignKeyConstraintName("FK_Person_Case") 
      .Cascade.AllDeleteOrphan(); 
    } 
} 

Si j'utilise SessionSource.BuildSchema pour une base de données de test, cela génère une table de personne ayant une colonne CASEID annulable. Je n'ai pas trouvé un moyen pour que cela fonctionne avec un champ CaseId non nullable sans associations bidirectionnelles. Les instructions (pseudo) SQL exécutées:

  1. INSERT INTO Case ...
  2. sélectionnez Identité @@
  3. INSERT INTO Person/* (toutes les colonnes sauf CASEID) */
  4. sélectionnez Identité @@
  5. MISE À JOUR Person SET CASEID =? WHERE Id =?; @ P0 = 2, @ p1 = 1
+0

LOL ... avec une relation , la plupart des gens omettent la valeur multiple fin quand ils se réfèrent à une relation unidirectionnelle! Comment mappez-vous la propriété Persons sur Case? –

Répondre

1

Je pense que vous pourriez ne pas avoir de chance ici. Les documents au http://nhibernate.info/doc/nh/en/index.html#collections-onetomany indiquent:

Si la colonne d'une association est déclarée NOT NULL, NHibernate peut provoquer des violations de contraintes lors de la création ou de la mise à jour de l'association. Pour éviter ce problème, vous devez utiliser une association bidirectionnelle avec la fin de nombreuses valeurs (l'ensemble ou le sac) marqué comme inverse = "true"

Questions connexes