Andrzej Gis
Andrzej Gis

Reputation: 14306

Nhibernate on collection item removed

I have 2 classes:

public class Entry{
  ...
  public virtual IsDeleted {get;set;}
  public virtual int MyClsId {get;set;}
  public virtual MyClass MyCls {get;set;}
}

public class MyClass{
  ...
  public virtual ICollection<Entry> Entries {get;set;}
}

When I remove an item from MyClass.Entries I don't actually want to delete it nor kill the realtion. I just want to set Entry.IsDeleted to true and I still want the Entry to keep myClass'es Id;

myClassObj.Entries.Remove(myEntry); // after this line myEntry.MyCls.Id 
                                    // should stay intact. myEntry.IsDeleted 
                                    // should be set to true;

How can I do that? I tried with interceptors, but couldn't get it to work.

edit

Mappings:

Apart form mapping the fields I use:

MyClassMap : ...
{
  HasMany(x => Entries).KeyColumn("MyClsId");
}

Upvotes: 0

Views: 1119

Answers (5)

Andrzej Gis
Andrzej Gis

Reputation: 14306

I had to create an additional property in MyClass and this seems to be the only working solution.

public virtual IEnumerable<Entry> NotDeletedEntries{get{return Entries.Where(x=>x.IsDeleted == false);}}

Upvotes: 0

zszep
zszep

Reputation: 4458

One way to achieve what you want is not to use the entity directy but a DTO which is copy of your entity (with all the collection items). You perform the remove action on the DTO (so the deleted collection item is invisible to the application) and later on when you want to save the entity you just synchronize it with the DTO (for the removed collection item you set the IsDeleted flag to true). A little bit more of work, but it achieves what you want to do.

Upvotes: 1

Radim K&#246;hler
Radim K&#246;hler

Reputation: 123861

If I do understand your scenario correctly you would like to have a Delete action which would at the end:

  • keep the relation
  • mark the item as IsDeleted
  • do not keep it in the collection of the parent (here I am not sure, but if needed, we have the solution below)

1) To keep the relation we simply won't call delete all the way.

We can introduce a method on the Parent RemoveEntry

public class MyClass 
{
  public virtual void RemoveEntry(Entry entry) // or by index, name
  {
     // some checks over Entries collection
     entry.IsDeleted = true;
  }
}

when the MyClass instance is updated session.Update(myClass), all the entries will be as well

2) To mark it as IsDeleted, we will just append cascading (see more here fluent mapping

MyClassMap : ...
{
  HasMany(x => Entries)
   .KeyColumn("MyClsId")
   .Cascade.All()
}

3) To remove that item from a lazy load of the Parent children collection, we can append a where clause to the collection mapping. See example here: where clause in the mapping

MyClassMap : ...
{
  HasMany(x => Entries)
    .KeyColumn("MyClsId")
    .Cascade.All()
    .Where("IsDeleted = 0"); // that will load only IsDeleted == false lazily
}

More about where clause in documentation: 6.2. Mapping a Collection

Upvotes: 1

Felipe Oriani
Felipe Oriani

Reputation: 38598

In this case, you have to update your entity instead of Delete. Try to change your mapping with

// set cascade to all to add/update/delete this childs by parent.
HasMany(x => Entries).KeyColumn("MyClsId").Cascade.All();

onde the MyClass create a method to update it:

public class MyClass{
  ...
  public virtual ICollection<Entry> Entries {get;set;}

  public void DeleteEntry(Entry entry)
  {
      entry.IsDelete = true;   
  }
}

and when you want to set an Entry object to IsDeleted to true your call the DeleteEntry method passing the object and just persist the MyClass instance, the childs will be persisted together.

session.SaveOrUpdate(myClassObj);

Upvotes: 1

Colm Prunty
Colm Prunty

Reputation: 1620

It doesn't seem like you actually want to remove this from the collection, maybe it would make more sense to put a method on Entry that's like

public void Delete(){
    IsDeleted = true;
}

and instead of

myClassObj.Entries.Remove(myEntry);

do

myEntry.Delete();

Upvotes: 1

Related Questions