Search code examples
c#wcf-data-servicesodata

Removing items from a collection using WCF Data Services


I have a checked listbox in a Windows Forms app that allows the user to assign one or more security groups to a selected user.

Using WCF Data Services, I am able to populate the box without a problem. However, as the user changes selections in the box and tries to save those changes, I run into issues.

Here is the code, with comments to explain my logic.

private void ProcessSecurityGroupSelection_Original()
{
  //Get a reference to the selected user, including the associated SecurityGroups.
  var user = _ctx.Users
    .AddQueryOption("$filter", "UserID eq " + ((DataService.User)lstUsers.SelectedItem).UserID)
    .AddQueryOption("$expand", "SecurityGroups")
    .First();

  //Remove all the SecurityGroups so we can replace them.
  user.SecurityGroups.Clear();

  foreach (var selectedGroup in lstSecurityGroups.CheckedItems)
  {
    //Loop through the selected SecurityGroups, linking and adding each SecurityGroup to the User object.
    var securityGroup = (from sg in _ctx.SecurityGroups
                 where sg.SecurityGroupID == ((DataService.SecurityGroup)selectedGroup).SecurityGroupID
                 select sg).First();

    _ctx.AddLink(user, "SecurityGroups", securityGroup);

    user.SecurityGroups.Add(securityGroup);
  }

  _ctx.UpdateObject(user);
  _ctx.SaveChanges();
}

When the code hits the AddLink method for a SecurityGroup that had previously been selected, I get an error stating "The context is already tracking the relationship." It doesn't appear that the Clear() method removes any links in the context.

How do I go about removing the existing links, or am I approaching this all wrong?


Solution

  • One way to remove the links is to add an event like the following:

    private void lstSecurityGroups_ItemCheck(object sender, ItemCheckEventArgs e)
    {
        if (e.NewValue == CheckState.Unchecked)
        {
            _ctx.DetachLink(user, "SecurityGroups", securityGroup);
        }
        else if (e.NewValue == CheckState.Checked)
        {
            _ctx.AddLink(user, "SecurityGroups", securityGroup);
        }
    }
    

    Note that DeleteLink will mark the entity for deletion also, which will cause an error if called multiple times. If you just want to remove the link, use DetachLink.