2010-03-30 7 views
4

Je ne peux pas obtenir ma tête pourquoi cela ne fonctionne pas ..collection Courant Nhibernate ManyToMany - ne pas sauver les associations

J'ai un modèle d'entité relativement propre composé de Poços créé avec DDD à l'esprit (tout probablement pas suivant la plupart des règles même vaguement). J'utilise Fluent NHibernate pour faire la cartographie. J'utilise également SchemaExport pour créer le schéma de base de données, avec un minimum d'informations de ma part sur la façon de le faire. NHibernate est libre de choisir la meilleure façon.

J'ai deux entités avec des relations plusieurs-à-plusieurs les unes avec les autres (code non-intéressant supprimé); MediaItem et Tag; MediaItems peut avoir de nombreux tags, les tags peuvent être appliqués à de nombreux MediaItems, et je veux des collections des deux côtés pour que je puisse facilement y accéder.

(Un peu d'un problème de mise en forme ci-dessous, désolé)

  • MediaItem:

    public class MediaItem 
    { 
    
    private IList<Tag> _tags; 
    
    public virtual long Id { get; set; } 
    
    public virtual string Title { get; set; } 
    
    public virtual IEnumerable<Tag> Tags { get { return _tags; } } 
    
    public MediaItem() 
    { 
        _tags = new List<Tag>(); 
    } 
    
    public virtual void AddTag(Tag newTag) 
    { 
        _tags.Add(newTag); 
        newTag.AddMediaItem(this); 
    } 
    

    }

  • Tag:

    public class Tag {

    private IList<MediaItem> _mediaItems; 
    public virtual long Id { get; set; } 
    public virtual string TagName { get; set; } 
    public virtual IEnumerable<MediaItem> MediaItems { get { return _mediaItems; } } 
    
    public Tag() 
    { 
        _mediaItems = new List<MediaItem>(); 
    } 
    
    protected internal virtual void AddMediaItem(MediaItem newItem) 
    { 
        _mediaItems.Add(newItem); 
    } 
    

    }

J'ai essayé d'être intelligent sur seulement d'exposer les collections comme IEnumerable, et ne permettant d'ajouter des éléments à travers les méthodes. J'entends aussi que seul un côté de la relation devrait être responsable de cela - donc le AddMediaItem() artificiel sur Tag.

Le MediaItemMap ressemble à ceci:

public class MediaItemMap : ClassMap<MediaItem> 
{ 
    public MediaItemMap() 
    { 
     Table("MediaItem"); 

     Id(mi => mi.Id); 

     Map(mi => mi.Title); 

     HasManyToMany<Tag>(mi => mi.Tags) 
      .Access.CamelCaseField(Prefix.Underscore) 
      .Cascade.SaveUpdate(); 
    } 
} 

La cartographie Tag ressemble à ceci:

public class TagMap : ClassMap<Tag> 
{ 
    public TagMap() 
    { 
     Table("Tag"); 

     Id(t => t.Id); 

     Map(t => t.TagName); 

     HasManyToMany<MediaItem>(mi => mi.MediaItems) 
      .Access.CamelCaseField(Prefix.Underscore) 
      .Inverse(); 
    } 
} 

Maintenant, j'ai un code de test qui supprime le schéma de base de données, recrée (depuis que je suis fusil de chasse débogage mon cerveau ici), puis exécute le code simple suivant:

Tag t = new Tag { TagName = "TestTag" }; 
MediaItem mi = new MediaItem { Title = "TestMediaItem" }; 

mi.AddTag(t); 

var session = _sessionFactory.OpenSession(); 

session.Save(mi); 

Yep, c'est un code de test, il ne survivra jamais au problème dans ce post.

Le MediaItem est enregistré, tout comme le tag. Cependant, l'association entre eux n'est pas. NHibernate crée la table d'association "MediaItemsToTags", mais n'essaie pas d'y insérer quoi que ce soit.

Lors de la création de l'ISessionFactory, je spécifie ShowSQL() - afin que je puisse voir tous les DDL envoyés au serveur SQL. Je peux voir l'instruction d'insertion pour les tables MediaItem et Tag, mais il n'y a pas d'insertion pour MediaItemsToTags.

J'ai expérimenté avec beaucoup de différentes versions de ceci, mais je ne peux pas sembler le casser. La cascade est un problème possible, j'ai essayé avec Cascade.All() des deux côtés, Inverse() des deux côtés etc., mais pas de dés.

Quelqu'un peut-il me dire quelle est la bonne façon de mapper ceci pour que NHibernate stocke réellement l'association chaque fois que je stocke mon MediaItem?

Merci!

Répondre

1

Vous devez définir les nombreux à plusieurs table et parents et enfants colonnes clés:

public class MediaItemMap : ClassMap<MediaItem> 
{ 
    public MediaItemMap() 
    { 
     Table("MediaItem"); 

     Id(mi => mi.Id); 

     Map(mi => mi.Title); 

     HasManyToMany<Tag>(mi => mi.Tags) 
      .Table("MediaItemsToTags").ParentKeyColumn("Id").ChildKeyColumn("Id") 
      .Access.CamelCaseField(Prefix.Underscore) 
      .Cascade.SaveUpdate(); 
    } 
} 

La syntaxe est identique à TagMap parce que les deux colonnes clés sont nommées « Id ».

+0

Bonjour, Merci pour votre suggestion. Je pensais que ParentKeyColumn et ChildKeyColumn étaient utilisés pour nommer les colonnes de la table définie par Table(). Donc, je suis vraiment plein d'espoir pour cela, mais malheureusement, il m'a donné une erreur quand j'ai essayé d'initialiser le ISessionFactory: colonne répétée dans la cartographie pour la collection: colonne PhotoAlbumLibrary.Entities.MediaItem.Tags: Id Ainsi, alors que cela pourrait Soutenez ma théorie, j'admettrai volontiers que j'en connais trop peu à ce sujet. Je ne pense pas, cependant, ce serait une exigence de nommer les champs d'identité pour chaque entité différemment? –

+0

Okey, je viens de faire un test. Dans le mapping pour les champs Id, j'ai changé le nom de la colonne comme ceci: Id (mi => mi.Id, "MediaItemId"); (et la même chose pour Tag, seulement avec "TagId"). J'ai également fait les changements que vous avez suggérés, en ajoutant les tables, ParentKeyColumn et ChildKeyColumn avec les noms propres, et, malheureusement, je suis toujours dans la même situation - NHibernate ne tente pas d'insérer quoi que ce soit dans la table MediaItemsToTags. J'ai aussi essayé de faire une session.Sauvegardez sur l'objet tag juste au cas, mais sans effet. –

+1

J'ai manqué cela avant, mais vous devez appeler 'session.Flush()' après 'session.Save (mi)'. Les objets MediaItem et Tag sont enregistrés sans vidage, car NHibernate doit les insérer afin que les clés générées automatiquement soient créées par la base de données. Je suis confiant que les changements que vous avez déjà faits en appelant 'session.Flush()' fonctionneront. –

Questions connexes