i have a problem with Nhibernate collection mapped asSet, in few word when i add new item to collection all other item are lost.
but what is more strange is that those appens only once, every following insert give no problem since i restart app
this my object:
public class Attivita : BaseObject<Attivita, int> {
public override int Id { get; set; }
private ICollection<SAL> _statiAvanzamentoLavori = new List<SAL>();
public virtual IEnumerable<SAL> StatiAvanzamentoLavori {
get { return _statiAvanzamentoLavori.ToArray(); }
}
public virtual void AddSAL(DateTime dataRiferimento, DateTime dataAvvioPrevisto, DateTime dataConclusionePrevista) {
if (!(_statiAvanzamentoLavori.Any(x => x.DataRiferimento == dataRiferimento))){
SAL sal = new SAL{
DataRiferimento = dataRiferimento,
DataAvvioPrevisto = dataAvvioPrevisto,
DataConclusionePrevista = dataConclusionePrevista,
};
_statiAvanzamentoLavori.Add(sal);
}
}
}
public class SAL : EquatableObject<SAL>
{
protected internal virtual int id {get; set;}
public virtual DateTime DataRiferimento {get; set;}
public virtual DateTime DataAvvioPrevisto {get; set;}
public virtual DateTime DataConclusionePrevista {get; set;}
}
BaseObject
override Equals using ID property
EquatableObject
override Equals comparing all object property
the maps:
public AttivitaMap()
{
Table("Attivita_T041");
Id(x => x.Id)
.Column("Kint_T041_IdAttivita").GeneratedBy.Assigned();
HasMany<SAL>(x => x.StatiAvanzamentoLavori)
.Access.CamelCaseField(Prefix.Underscore)
.KeyColumns.Add("int_T018_IdAttivita", x => x.UniqueKey("IX18_1"))
.ForeignKeyConstraintName("FK18_IdAtt") .Not.LazyLoad().Cascade.All();
}
}
public SALMap()
{
Table("SAL_T018");
Id(x => x.id)
.Column("Kint_T018_IdSAL")
.GeneratedBy.Identity();
Map(x => x.DataRiferimento).UniqueKey("IX18_1")
.Not.Nullable();
Map(x => x.DataAvvioPrevisto);
Map(x => x.DataConclusionePrevista).Not.Nullable();
}
and finally the test:
[Test]
public void AttivitaRepositoryCanInsertSALOnNotEmptyCollection() {
var attivita = fixture.Create<Attivita>();
var SAL1 = fixture.Create<SAL>();
var SAL2 = fixture.Create<SAL>();
attivita.AddSAL(SAL1.DataRiferimento, SAL1.DataAvvioPrevisto, SAL1.DataConclusionePrevista);
using (UnitOfWork uow = GetUnitOfWork()) {
uow.Attivita.Update(attivita);
uow._session.Transaction.Commit();
}
using (UnitOfWork uow = GetUnitOfWork()) {
attivita = uow._session.Get<Attivita>(attivita.Id);
// this test pass
attivita.StatiAvanzamentoLavori.Count().Should().Be(1);
attivita.AddSAL(SAL2.DataRiferimento, SAL2.DataAvvioPrevisto, SAL2.DataConclusionePrevista, SAL2.StatoAvanzamentoAttivita);
uow.Attivita.Update(attivita);
uow._session.Transaction.Commit();
}
using (UnitOfWork uow = GetUnitOfWork()) {
// this test fails: expected 2 found 1
uow._session.Get<Attivita>(attivita.Id).StatiAvanzamentoLavori.Count().Should().Be(2);
var SAL3 = fixture.Build<SAL>().With(x => x.StatoAvanzamentoAttivita, statoAvanzamentoTest).Create();
using (UnitOfWork uow = GetUnitOfWork()) {
attivita = uow._session.Get<Attivita>(attivita.Id);
attivita.AddSAL(SAL3.DataRiferimento, SAL3.DataAvvioPrevisto, SAL3.DataConclusionePrevista, SAL3.StatoAvanzamentoAttivita);
uow.Attivita.Update(attivita);
uow._session.Transaction.Commit();
}
using (UnitOfWork uow = GetUnitOfWork()) {
uow._session.Get<Attivita>(attivita.Id).StatiAvanzamentoLavori.Count().Should().Be(3);
// this test fails: expected 3 found 2
}
}
}
so when i add the second sal the first is lost but when i add the third the second remain, why??
looking at SQL log i see that when i add the second SAL un update is fired to SAL TABLE settings IdAttivita to NULL, so link to Attivita is lost
i read here that removing and inserting all links is behaviour is by design with Bag collection but i have SET with primary key
More strange if i change AsSet
to AsBag
(or simply remove AsAet
) for collection mapping all works fine, but i need Set for other things (like multiple fetch)