我在Windows窗体应用程序中有一个选中的列表框,允许用户将一个或多个安全组分配给选定的用户。
使用WCF数据服务,我可以毫无问题地填充框。但是,当用户更改框中的选择并尝试保存这些更改时,我遇到了问题。
这是代码,用注释来解释我的逻辑。
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();
}
当代码点击先前已被选中的SecurityGroup的AddLink方法时,我收到一条错误,指出“上下文已经在跟踪关系”。 Clear()方法似乎不会删除上下文中的任何链接。
如何删除现有链接,或者我是否接近这一切?
答案 0 :(得分:2)
我遇到了与silverlight项目相同的问题。我已经采用了适合我的解决方案并将其应用于您的User / SecurityGroup模型。
将以下内容添加到您的用户类:
public User()
{
this.SecurityGroups.CollectionChanged += (sender, e) =>
{
if (e.Action == Add)
{
foreach (SecurityGroup AddedGroup in e.NewItems)
AddSecurityGroup(AddedGroup);
}
if (e.Action == Remove)
{
foreach (SecurityGroup RemovedGroup in e.OldItems)
RemoveSecurityGroup(RemovedGroup);
}
};
..... rest of constructor
}
public void AddSecurityGroup(SecurityGroup secGroup)
{
LinkDescriptor descriptr = _ctx.GetLinkDescriptor(this, "SecurityGroups", secGroup);
if (descriptr == null)
_ctx.AddLink(this, "SecurityGroups", secGroup);
else if (descriptr.State == EntityStates.Deleted)
_ctx.DetachLink(this, "SecurityGroups", secGroup);
}
public void RemoveSecurityGroup (SecurityGroup secGroup)
{
LinkDescriptor descriptr = _ctx.GetLinkDescriptor(this, "SecurityGroups", secGroup);
if (descriptr == null)
{
_ctx.AttachLink(this, "SecurityGroups", secGroup);
_ctx.DeleteLink(this, "SecurityGroups", secGroup);
}
else if (descriptr.State == EntityStates.Added)
_ctx.DetachLink(this, "SecurityGroups", secGroup);
else
_ctx.DeleteLink(this, "SecurityGroups", secGroup);
}
现在删除该行:
_ctx.AddLink(user, "SecurityGroups", securityGroup);
来自上面的代码。
答案 1 :(得分:1)
删除链接的一种方法是添加如下事件:
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);
}
}
请注意,DeleteLink
也会标记要删除的实体,如果多次调用会导致错误。如果您只想删除链接,请使用DetachLink
。
答案 2 :(得分:1)
根据Aiston的回答,我准备了一套扩展来帮助处理添加然后删除和删除然后添加的链接。
我更喜欢以一些小的性能成本来避免魔术字符串
public static class DataServiceContextExtensions
{
public static void AddOrAttachLink<TSource>(this DataServiceContext context, object source, Expression<Func<TSource>> sourceProperty, object target)
{
AddOrAttachLink(context, source, sourceProperty.GetExpressionMemberInfo().Name, target);
}
public static void AddOrAttachLink<TSource, TTarget>(this DataServiceContext context, TSource source, Expression<Func<TSource, ICollection<TTarget>>> sourceProperty, TTarget target)
{
AddOrAttachLink(context, source, sourceProperty.GetExpressionMemberInfo().Name, target);
}
public static void AddOrAttachLink(this DataServiceContext context, object source, string propertyName, object target)
{
var descriptor = context.GetLinkDescriptor(source, propertyName, target);
if(descriptor == null)
{
context.AddLink(source, propertyName, target);
}
else if(descriptor.State == EntityStates.Deleted)
{
context.DetachLink(source, propertyName, target);
context.AttachLink(source, propertyName, target);
}
}
public static void DeleteOrDetachLink<TSource>(this DataServiceContext context, object source, Expression<Func<TSource>> sourceProperty, object target)
{
DeleteOrDetachLink(context, source, sourceProperty.GetExpressionMemberInfo().Name, target);
}
public static void DeleteOrDetachLink<TSource, TTarget>(this DataServiceContext context, TSource source, Expression<Func<TSource, ICollection<TTarget>>> sourceProperty, TTarget target)
{
DeleteOrDetachLink(context, source, sourceProperty.GetExpressionMemberInfo().Name, target);
}
public static void DeleteOrDetachLink(this DataServiceContext context, object source, string propertyName, object target)
{
var descriptor = context.GetLinkDescriptor(source, propertyName, target);
if(descriptor == null)
{
context.AttachLink(source, propertyName, target);
context.DeleteLink(source, propertyName, target);
}
else if(descriptor.State == EntityStates.Added)
{
context.DetachLink(source, propertyName, target);
}
else
{
context.DeleteLink(source, propertyName, target);
}
}
public static MemberInfo GetExpressionMemberInfo(this Expression expression)
{
var lambda = (LambdaExpression)expression;
MemberExpression memberExpression;
if(lambda.Body is UnaryExpression)
{
var unaryExpression = (UnaryExpression)lambda.Body;
memberExpression = (MemberExpression)unaryExpression.Operand;
}
else
{
memberExpression = (MemberExpression)lambda.Body;
}
return memberExpression.Member;
}
}
用法:
var ctx = new YourContext();
ctx.AddOrAttachLink(addTo, () => addTo.Collection, toAdd);
ctx.DeleteOrDetachLink(removeFrom, () => removeFrom.Collection, toRemove);