-1

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)

Community
  • 1
  • 1
gt.guybrush
  • 1,320
  • 3
  • 19
  • 48
  • `SAL1` and `SAL2` looks to be created the same way. If their equality test considers them equal, a set should ignore the second add by contract. – Frédéric Feb 07 '17 at 00:14

1 Answers1

-1

As answered by Nhibernate developer on their bugtracker problem was mixing Equals method: Value object must be compared by their properties and entity by their id

My fault was using peropery comparison with the entity SAL

So i swtich it to use BaseObject and all works fine

gt.guybrush
  • 1,320
  • 3
  • 19
  • 48