Recursive saving on a related collection (newbie question)

Posts   
 
    
RomKo
User
Posts: 4
Joined: 18-Nov-2009
# Posted on: 18-Nov-2009 21:11:22   

Hey,

I am fairly green behind the ears with LLBLGen, so please forgive me if the answer should be obvious from documentation. Anyway, here goes:

I have Announcement entities which are in a m:n relation to Organization entities. When editing a single Announcement, I would like to set which Organizations it corresponds with. Essentially, I am dealing with updating the collection of "organizations" that a given "announcement" is related to.

Here is my attempt at the code:

This would have happened at some point before the method I'm exploring:


announcement = new AnnouncementEntity(id);

This is the code I'm having trouble with:



            announcement.AnnouncementOrganization.Clear();
            foreach (OrganizationEntity org in selectedOrganizations)
            {
                AnnouncementOrganizationEntity currentJoin = new AnnouncementOrganizationEntity();
                currentJoin.Announcement = announcement;
                currentJoin.Organization = org;
                announcement.AnnouncementOrganization.Add(currentJoin);
            }
            announcement.Save(true); 

The trouble is getting the Clear() to be persisted. New relation entities get created, but old ones aren't getting removed. As I understand from documentation, I need to track remove actions using a RemovedEntitiesTracker, and then use a Unit of Work to make removing the relation entities, and adding new ones occur in the same transaction. However, I suspect I'm making it much more complicated than it needs to be.

Ideally, I would want something that works something like this:


            announcement.Organizations.Clear();
            foreach (OrganizationEntity org in selectedOrganizations)
            {
                announcement.Organizations.Add(org);
            }
            announcement.Save(true); 

Thanks!

RomKo
User
Posts: 4
Joined: 18-Nov-2009
# Posted on: 18-Nov-2009 21:57:42   

Forgot to mention, I'm using self servicing, v2.6 Final

RomKo
User
Posts: 4
Joined: 18-Nov-2009
# Posted on: 18-Nov-2009 22:10:45   

There is a related topic that I've found: http://www.llblgen.com/TinyForum/Messages.aspx?ThreadID=649&HighLight=1

From what I understand, I am on the right path. I will have to track the AnnouncementOrganization entities that I remove from the collection, and use a UnitOfWork to group the entity deletion actions in the same transaction as the creation actions. Will post my code once this is actually working.

RomKo
User
Posts: 4
Joined: 18-Nov-2009
# Posted on: 19-Nov-2009 00:05:08   

Here is what I ended up with. I gave up on using UnitOfWork since the default order inserts before deletes. I don't like having the delete as a separate step, and any advice on improving this code would be appreciated!


            foreach (OrganizationEntity org in selectedOrganizations)
            {
                AnnouncementOrganizationEntity currentJoin = new AnnouncementOrganizationEntity();
                currentJoin.Announcement = announcement;
                currentJoin.Organization = org;
                announcement.AnnouncementOrganization.Add(currentJoin);
            }
            announcement.AnnouncementOrganization.DeleteMultiManyToOne(announcement, null);
            announcement.Save(true); 

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 19-Nov-2009 06:26:58   

You should read Deleting one or more entities from the persistent storage.

This call is ok as you don't need the entities to delete fetched, you just want to delete them. So it's ok.

announcement.AnnouncementOrganization.DeleteMultiManyToOne(announcement, null);

I would do that this way (approximate code):

AnnouncementOrganizationCollection mnToAdd = new AnnouncementOrganizationCollection();
foreach (OrganizationEntity org in selectedOrganizations)
{
    AnnouncementOrganizationEntity currentJoin = new AnnouncementOrganizationEntity();
    currentJoin.Announcement = announcement;
    currentJoin.Organization = org;
    mnToAdd(currentJoin);
}

try
{
    Transaction tx = new Transaction(IsolationLevel.ReadCommited, "SaveNewOrganizations");

    tx.Add(announcement.AnnouncementOrganization);
    announcement.AnnouncementOrganization.DeleteMultiManyToOne(announcement, null);

    tx.Add(mnToAdd);
    mnToAdd.Save();
    
    tx.Commit();
}
catch
{
    tx.Rollback();
}
...

Some points

  • I use a Transactions because you are executing two actions (Deletes + Inserts) and you want to do those actions in an atomic way.

  • I used a separate AnnouncementOrganizationCollection coz is more clean in this situation. If you use announcement.AnnouncementOrganization.Add(... and lines after announcement.AnnouncementOrganization.Delete(... it's not 100% clear. But should work your way too.

  • In fact, a better choice for the delete would be

mnToAdd.DeleteMulti(AnnouncementOrganizationFields.IdAnnouncement = annoucement.IdAnnoucement)

coz it doesn't trigger lazy-loading.

  • You don't need to track removed entities in this case. That is used if you have a collection and you are removing entities in a different parts of your code. And "Clear" isn't taken into account for Tracking removal.

  • If you like UnitOfWork, you can specify a custom order in which the actions are executed. Read this.

David Elizondo | LLBLGen Support Team