Como cascata Salvar com compositeId em NHibernate?
-
07-07-2019 - |
Pergunta
Eu tenho um simples de três tabela DB com muitos-para-muitos relação.
A(id, Name)
B(id, Name)
AB(AId, BId) references A and B
As classes correspondentes:
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 */ }
}
Eu fiz mapeamentos com 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");
}
}
Então, agora eu quero ser capaz de fazer algo assim
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);
Mas em saveOrUpdate Eu obter TransientObjectException . Então, para passar por cima eu preciso saveOrUpdate A e B antes de salvar o AB. Mas parece que deveria haver outra maneira de manter esses objetos em um único saveOrUpdate .
Existe alguma maneira de ponto no mapeamento AB para Cascade A e B em salvar operação?
UPDATE:
Eu removi a Lista de ligações AB em uma classe para maior clareza. Originalmente era:
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);
Obrigado!
Solução
Eu fiz esta pergunta no grupo de usuários nhibernate. E a resposta foi que não há nenhuma maneira de propagar qualquer operação usando composite-id (talvez nos futuros lançamentos será possível).
Então eu fiz uma solução alternativa. I colocado duas referências (muitos-para-um com cascata) em vez de compositeId e adicionou-Id para a tabela AB e entidade AB. Agora ele está trabalhando e A e B são entidades em cascata.
Outras dicas
Apenas uma nota lateral, mas por que você crie uma classe AB? Se a relação entre estas 2 classes não tem nenhum propriedades extras, então sua classe 'AB' não é necessário ...
Para responder à sua pergunta:. Você pode definir opções em cascata em um relacionamento no NHibernate
Em Fluent NHibernate, eu acho que você vai ter que fazê-lo como este:
public class FooMap : ClassMap<Foo>
{
public FooMap()
{
HasMany(x => x.Bars).Cascade.AllDeleteOrphan();
}
}
(note que você tem que aplicá-lo à sua situação, mas o retorno collectionmapping uma propriedade Cascade, para que possa definir quais cascata técnica que você deseja aplicar)
Na verdade, eu consegui fazê-lo funcionar com muita facilidade, e os olhares de código muito não seca!
Aqui está o meu caso parecia:
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();
}
}
Espero que ajude alguém olhando para o mesmo problema no futuro.