LINQ to SQL表可扩展性方法

时间:2009-12-22 23:52:00

标签: linq-to-sql extensibility

如果我有一个LINQ to SQL表,其中有一个名为alias的字段。

然后有一个名为OnAliasChanging(字符串值)的方法存根;

我想要做的是获取值,检查数据库是否已存在该值,然后将值设置为已输入的值。

所以我可能会将我的别名从“griegs”更改为“slappy”,如果存在slappy,那么我想恢复已经存在的“griegs”值。

所以我有;

    partial void OnaliasChanging(string value)
    {
        string prevValue = this.alias;
        this.Changed = true;
    }

当我检查prevValue的值时,它总是为空。

如何获取字段的当前值?

更新

如果我实现类似的东西;

    partial void OnaliasChanging(string value)
    {
        if (this.alias != null)
            this.alias = "TEST VALUE";
    }

它会进入一个不健康的infinte循环。

如果我检查别名是否已经==“TEST VALUE”,则infinate循环仍然保留,因为该值始终是原始值。

有办法做到这一点吗?

2 个答案:

答案 0 :(得分:1)

你发布的代码片段不适合任何合理的解释,为什么你最终会有无限循环。我认为this.alias可能是一个属性,而不是字符大小写所暗示的字段,但需要看到更多。如果它是属性,那么在设置属性之前调用OnAliasChanging方法;因此,尝试在同一方法中再次设置它将始终导致无限循环。通常,设计此方案的方法是在Cancel OnXyzChanging衍生产品中实施EventArgs属性,或者将旧值保存在OnXyzChanging方法中,然后执行检查如果您不能使用第一个(更好)选项,则在OnXyzChanged方法中回滚/滚动。

从根本上说,你要做的事情一般不是很好的设计,而且违背了Linq to SQL的原则。 Linq to SQL实体应该是一个POCO,根本不了解兄弟实体或底层数据库。对每个属性更改执行重复检查不仅需要访问DataContextSqlConnection,还会导致技术上称为副作用(打开新的数据库连接和/或默默地丢弃财产变更)。这种设计只是为了在路上发生神秘的撞车而尖叫。

事实上,您的特定场景是DataContext类首先可扩展的主要原因之一。这种类型的操作属于那里。假设此处的实体名为User,其中包含表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约束,所以这个方法可以简单地记录下来并用作安全尝试更改名称的方法,而不会在以后发生约束违规的风险(虽然总有某些风险 - 除非将所有内容放入事务或存储过程中,否则仍然可能存在竞争条件)。

如果您绝对必须限制对底层属性的访问,则执行此操作的一种方法是隐藏原始属性并创建只读包装器。在Linq设计器中,单击Alias属性,然后在属性表上将访问更改为Internal,将名称更改为{{ 1}}(但不要触及来源!)。最后,为实体创建一个部分类(我将在与AliasInternal部分类相同的文件中执行此操作)并为该属性编写只读包装:

MyDataContext

您还必须将partial class User { public string Alias { get { return AliasInternal; } } } 方法中的Alias引用更新为ChangeAlias

请注意,这可能会破坏尝试对新AliasInternal包装器进行过滤/分组的查询(我相信Linq会抱怨它无法找到SQL映射)。该属性本身可以作为访问器使用,但如果您需要在Alias上执行查找,那么您可能需要在Alias中使用另一个GetUserByAlias辅助方法,一个可以执行“真实的“查询MyDataContext

当你决定除了域逻辑之外你想要搞乱Linq的数据访问逻辑时,事情开始有点冒险,这就是为什么我在上面建议你只保留AliasInternal属性并适当记录其用法。 Linq是围绕乐观并发而设计的;通常,当您需要在应用程序中强制执行UNIQUE约束时,请等待实际保存更改,然后在发生约束时处理约束违规。如果你想立即做到这一点,你的任务会变得更加困难,这就是这种冗长和普遍存在的原因。

再一次 - 我建议反对创建只读包装器的附加步骤;无论如何,我已经提出了一些代码,以防你的规范出于某种原因需要它。

答案 1 :(得分:0)

是否因为OnaliasChanging在初始化期间触发而挂起,因此您的支持字段(别名)永远不会被初始化,因此它始终为空?

没有更多的背景,这对我来说就是这样。