您发布的代码片段并不能合理地解释为什么您最终会出现无限循环。我认为这this.alias
可能是一个属性,而不是字符外壳所暗示的字段,但需要查看更多内容。如果它是一个属性,那么您是OnAliasChanging
在设置属性之前调用该方法;因此,尝试以相同的方法再次设置它总是会导致无限循环。通常设计这个场景的方法是在你的派生中实现一个Cancel
属性OnXyzChanging
EventArgs
,或者在方法中保存旧值,如果你不能使用第一个(更好的)选项OnXyzChanging
,然后在方法中执行检查/回滚。OnXyzChanged
但是,从根本上说,您尝试做的不是很好的设计,而且特别违反了 Linq to SQL 的原则。Linq to SQL 实体应该是一个 POCO,根本不知道兄弟实体或底层数据库。对每个属性更改执行重复检查不仅需要访问DataContext
or SqlConnection
,而且还会导致技术上所谓的副作用(打开新的数据库连接和/或静默丢弃属性更改)。这种设计只会让路上发生神秘的车祸。
DataContext
实际上,您的特定场景是首先使该类可扩展的主要原因之一。这种类型的操作属于那里。假设这里的实体是User
用 table调用的Users
。
partial class MyDataContext
{
public bool ChangeAlias(Guid userID, string newAlias)
{
User userToChange = Users.FirstOrDefault(u => u.ID == userID);
if ((userToChange == null) || Users.Any(u => u.Alias == newAlias))
{
return false;
}
userToChange.Alias = newAlias;
// Optional - remove if consumer will make additional changes
SubmitChanges();
return true;
}
}
这封装了您要执行的操作,但不阻止消费者Alias
直接更改属性。 如果你能忍受这个,我会停在那里- 你的数据库本身应该仍然有一个 UNIQUE 约束,所以这个方法可以简单地记录下来并用作尝试更改名称的安全方法,而不会在以后冒违反约束的风险on (尽管总是存在一些风险 - 您仍然可以有竞争条件,除非您将这一切都放入事务或存储过程中)。
如果您绝对必须限制对基础属性的访问,一种方法是隐藏原始属性并制作只读包装器。在 Linq 设计器中,单击Alias
属性,然后在属性表上,将Access toInternal
和Name更改为AliasInternal
(但不要触摸Source!)。最后,为实体创建一个部分类(我会在与部分类相同的文件中执行此操作MyDataContext
)并为该属性编写一个只读包装器:
partial class User
{
public string Alias
{
get { return AliasInternal; }
}
}
您还必须将我们方法中的Alias
引用更新为.ChangeAlias
AliasInternal
请注意,这可能会破坏尝试在新Alias
包装器上过滤/分组的查询(我相信 Linq 会抱怨它找不到 SQL 映射)。该属性本身可以作为访问器正常工作,但如果您需要在 上执行查找,Alias
那么您可能需要另一个GetUserByAlias
帮助方法 in MyDataContext
,它可以在AliasInternal
.
当您决定除了域逻辑之外还想弄乱 Linq 的数据访问逻辑时,事情开始变得有点冒险,这就是为什么我在上面建议您只保留该Alias
属性并适当地记录其使用情况。Linq 是围绕乐观并发设计的;通常,当您需要在应用程序中强制执行 UNIQUE 约束时,您会等到实际保存更改后再处理约束冲突(如果发生)。如果您想立即执行此操作,您的任务就会变得更加困难,这就是这种冗长和普遍笨拙的原因。
再一次 - 我建议不要创建只读包装器的额外步骤;无论如何,我已经提供了一些代码,以防您的规范出于某种原因需要它。