Update a many-to-many

Posts   
 
    
sgay
User
Posts: 53
Joined: 23-Nov-2006
# Posted on: 16-May-2007 23:46:16   

This looks like a RTFM to me but I can't find where... feel free to point me to the appropriate page in the doc.

Assuming I have Users and Roles, with the following structure: User -> Roles via UserRole (n:m)

Then user.Roles is read-only because it is a many-to-many relation, and the only way to update it is by manipulating the intermediate UserRole entities.

Correct?

Then: can I use an EntityCollection to do this? I.e., if I load the UserRole entities for a given User in a standalone collection, then add a UserRole entity to the collection and remove another, then save the collection... will LLBLGen insert and delete records?

Or do I need to do it through user.UserRole to have inserts/deletes tracked?

Or do I need to manually delete/save each UserRole entity?

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 17-May-2007 04:16:40   

if I load the UserRole entities for a given User in a standalone collection, then add a UserRole entity to the collection and remove another, then save the collection... will LLBLGen insert and delete records?

Yes, It should do that.

David Elizondo | LLBLGen Support Team
sgay
User
Posts: 53
Joined: 23-Nov-2006
# Posted on: 17-May-2007 08:47:26   

daelmo wrote:

if I load the UserRole entities for a given User in a standalone collection, then add a UserRole entity to the collection and remove another, then save the collection... will LLBLGen insert and delete records?

Yes, It should do that.

That would be nice indeed. Unfortunately, the following code does insert a new entity in the database, but does not seem to delete the removed entity?

using llbl = MyProject.Namespace;

    llbl.HelperClasses.EntityCollection<llbl.EntityClasses.UserRoleEntity> roles =
        new llbl.HelperClasses.EntityCollection<llbl.EntityClasses.UserRoleEntity>(
            new llbl.FactoryClasses.UserRoleEntityFactory());

    adapt.FetchEntityCollection(roles, new
        RelationPredicateBucket(llbl.HelperClasses.UserRoleFields.UserId == 1234));

    roles.RemoveAt(roles.Count - 1);
    llbl.EntityClasses.UserRoleEntity n = new llbl.EntityClasses.UserRoleEntity();
    n.UserId = 1234;
    n.RoleId = 4321;
    roles.Add(n);

    adapt.SaveEntityCollection(roles);

Is this the normal behavior, or am I missing something?

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 17-May-2007 09:24:11   

Removing an entity from a collection won't delete it from the database when you save the collection. You's rather manually delete the entity. Or use a Unit Of Work object. Where you can add entities to be deleted, others to be saved and commit the UOW at the end to execute all the needed actions.

sgay
User
Posts: 53
Joined: 23-Nov-2006
# Posted on: 17-May-2007 10:22:48   

Walaa wrote:

Removing an entity from a collection won't delete it from the database when you save the collection. You's rather manually delete the entity.

Mmm... so it seems that the concept behind all this is that LLBLGen does not update collections i.e. propagates changes made to the collection (including new and removed elements) to the database, but rather uses collections to identify dependent entities and individually save these entities.

Then,

order.OrderItems.Add(item); // item becomes a dependent entity and will be saved ("added"). order.OrderItems.RemoveAt(3); // removed item is not a dependent entity anymore, full stop. adapter.DeleteEntity(order.OrderItems[3]); // explicitly deletes ("removes") the item.

Correct?

To come back to my original point, which was about updating a many-to-many relation: assuming I have User -> Role (n:m via UserRole), and the UI lets me pick roles for a user by checking them in a list, and then gives me back a user ID and a list of role IDs. I would need to do something like:

void UpdateRoles(int userID, int[] roleIDs)
{
    // should really wrap this in a transaction or a UnitOfWork

    adapter.DeleteEntitiesDirectly("UserRoleEntity", 
        new RelationPredicateBucket(UserRoleFields.UserId == userID));
    foreach (int roleID in roleIDs)
    {
        UserRoleEntity e = new UserRoleEntity();
        e.UserId = userID;
        e.RoleId = roleID;
        adapter.SaveEntity(e);
    }
}

Alternatively, I'd need to implement my own mechanism to track checked and unchecked roles, so I know which UserRoleEntity entities to selectively delete.

Do I make sense?

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 17-May-2007 10:42:45   

To come back to my original point, which was about updating a many-to-many relation: assuming I have User -> Role (n:m via UserRole), and the UI lets me pick roles for a user by checking them in a list, and then gives me back a user ID and a list of role IDs.

I'd take the first approach, delete all the entries and then add the new ones, preferably within a transaction.

And in case I have the UserRole entities to be deleted and thos to be inserted (instead of the user ID and role IDs) I'd have used a UOW.