Question

J'ai un DB simple à trois tables avec une relation plusieurs à plusieurs.

A(id, Name)
B(id, Name)
AB(AId, BId) references A and B

Les classes correspondantes:

public class A
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
}

public class B
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
}

public class AB
{
    public virtual A A { get; set; }
    public virtual B B { get; set; }
    public override bool Equals(object obj) { /* routine */ }
    public override int GetHashCode() { /* routine */ }
}

J'ai réalisé des correspondances avec Fluent NHibernate:

public class AMap : ClassMap<A>
{
    public AMap()
    {
        Id(x => x.Id).GeneratedBy.Identity();
        Map(x => x.Name);
    }
}

public class BMap : ClassMap<B> { /* The same as for A */ }

public class ABMap : ClassMap<AB>
{
    public ABMap()
    {
        CompositeId()
            .KeyReference(x => x.A, "AId")
            .KeyReference(x => x.B, "BId");
    }
}

Alors maintenant, je veux pouvoir faire quelque chose comme ça

var a = new A { Name = "a1" };    
var b = new B { Name = "b1" };    
var ab = new AB { A = a, B = b };

//session.SaveOrUpdate(a);
//session.SaveOrUpdate(b);
session.SaveOrUpdate(ab);

Mais sur SaveOrUpdate , je reçois une TransientObjectException . Donc, pour passer dessus, il faut SaveOrUpdate A et B avant de sauvegarder l’AB. Mais il semble qu'il devrait exister un autre moyen de conserver ces objets dans un seul SaveOrUpdate .

Existe-t-il un moyen de mettre en correspondance le mappage AB avec Cascade A et B lors de l'opération de sauvegarde?

UPDATE:

J'ai supprimé la liste des liens AB de la classe A pour plus de clarté. À l'origine, c'était:

public class A
{
    public A()
    {
        LinkToB = new List<AB>();
    }

    public virtual int Id { get; set; }
    public virtual string Name { get; set }
    public virtual IList<AB> LinkToB { get; private set; }
}

public class AMap : ClassMap<A>
{
    public AMap()
    {
        Id(x => x.Id).GeneratedBy.Identity();
        Map(x => x.Name);

        HasMany(x => x.LinkToB)
            .KeyColumn("AId")
            .Inverse()
            .Cascade.All()
            .AsBag();
    }
}

// inside the transaction
var a = new A { Name = "a1" };
var b = new B { Name = "b1" };

a.LinkToB.Add(new AB { A = a, B = b });
// session.SaveOrUpdate(b);
session.SaveOrUpdate(a);

Merci!

Était-ce utile?

La solution

J'ai posé cette question au groupe d'utilisateurs nhibernate. Et la réponse a été qu’il n’y avait aucun moyen de mettre en cascade une opération utilisant composite-id (ce sera peut-être possible dans les futures versions.)

Alors j'ai fait une solution de contournement. J'ai placé deux références (plusieurs en un avec cascade) à la place de CompositeId et ajouté un ID à la table AB et à l'entité AB. Maintenant, cela fonctionne et les entités A et B sont en cascade.

Autres conseils

Juste une note de côté, mais pourquoi avez-vous créé une classe AB? Si la relation entre ces 2 classes n'a pas de propriétés supplémentaires, alors votre classe 'AB' n'est pas nécessaire ...

Pour répondre à votre question, vous pouvez définir des options de cascade pour une relation dans NHibernate.

Dans Fluent NHibernate, je suppose que vous devrez le faire comme ceci:

public class FooMap : ClassMap<Foo>
{
    public FooMap()
    {
       HasMany(x => x.Bars).Cascade.AllDeleteOrphan();
    }
}

(notez que vous devez l'appliquer à votre situation, mais le mappage de la collection renvoie une propriété Cascade afin que vous puissiez définir la technique en cascade que vous souhaitez appliquer)

En fait, j'ai réussi à le faire fonctionner très facilement et le code a l'air trop sec!

Voici à quoi ressemblait mon cas:

public class MappingSample : ClassMap<DomainClass>
{
    public MappingCvTheme()
    {
        CompositeId()
            .KeyProperty(x => x.SomeProperty)
            .KeyReference(x => x.SomeReferencedObjectProperty);

        //here comes the trick, repeat the reference code:
        References(x => x.SomeReferencedObjectProperty).Cascade.All();
    }
}

J'espère que cela aidera quelqu'un qui recherche le même problème à l'avenir.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top