Методы расширения таблиц LINQ to SQL - PullRequest
0 голосов
/ 23 декабря 2009

Если у меня есть таблица 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";
    }

входит в бесконечный цикл, который вреден для здоровья.

Если я включу проверку, чтобы увидеть, является ли псевдоним уже == "TEST VALUE", бесконечный цикл все еще остается, поскольку значение всегда является исходным значением.

Есть ли способ сделать это?

Ответы [ 2 ]

1 голос
/ 23 декабря 2009

Фрагменты кода, которые вы разместили, не поддаются никакому правдоподобному объяснению того, почему вы в конечном итоге получили бесконечный цикл. Я думаю, что this.alias может быть свойством, в отличие от поля, которое подразумевает регистр символов, но нужно будет увидеть больше. Если это свойство, то вы вызываете метод OnAliasChanging до того, как свойство будет установлено; следовательно, попытка установить его снова одним и тем же методом всегда приведет к бесконечному циклу. Обычно способ разработки этого сценария состоит в том, чтобы либо реализовать свойство Cancel в производной OnXyzChanging EventArgs, либо сохранить старое значение в методе OnXyzChanging, а затем выполнить проверку / откат в методе OnXyzChanged если вы не можете использовать первый (лучший) вариант.

По сути, то, что вы пытаетесь сделать, это не очень хороший дизайн в целом и идет вразрез с принципами Linq to SQL, в частности. Предполагается, что сущность Linq to SQL - это POCO, не имеющая сведений об элементах-роднях или базовой базе данных. Для выполнения дуплексной проверки каждого изменения свойства требуется не только доступ к DataContext или SqlConnection, но и то, что технически можно назвать побочным эффектом (открытие нового соединения с базой данных и / или скрытое удаление свойства). менять). Такой дизайн просто кричит о таинственных авариях в будущем.

Фактически, ваш конкретный сценарий является одной из главных причин, по которым класс 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. Если вы можете с этим смириться, я бы тут же остановился - у вас все равно должно быть УНИКАЛЬНОЕ ограничение в вашей базе данных, поэтому этот метод можно просто документировать и использовать как безопасный способ попытаться изменить имя, не рискуя позже нарушением ограничения (хотя всегда есть некоторый риск - у вас все еще может быть состояние гонки, если вы не поместите все это в транзакцию или хранимую процедуру).

Если вы абсолютно должны ограничить доступ к базовому свойству, один из способов сделать это - скрыть исходное свойство и создать оболочку только для чтения. В конструкторе Linq щелкните свойство Alias и на листе свойств измените Access на Internal и Name на AliasInternal (но не коснитесь источника !). Наконец, создайте частичный класс для сущности (я бы сделал это в том же файле, что и частичный класс MyDataContext) и напишите оболочку только для чтения для свойства:

partial class User
{
    public string Alias
    {
        get { return AliasInternal; }
    }
}

Вам также нужно обновить Alias ссылки в нашем методе ChangeAlias до AliasInternal.

Имейте в виду, что это может нарушить запросы, которые пытаются фильтровать / группировать в новой оболочке Alias (я думаю, Linq будет жаловаться, что не может найти сопоставление SQL). Само свойство будет нормально работать как средство доступа, но если вам нужно выполнить поиск на Alias, то вам, вероятно, понадобится еще один вспомогательный метод GetUserByAlias в MyDataContext, который может выполнять «настоящий» запрос на AliasInternal.

Вещи начинают становиться немного рискованными, когда вы решаете, что хотите связываться с логикой доступа к данным Linq в дополнение к логике домена, поэтому я рекомендую выше просто оставить свойство Alias в покое и документ его использование соответствующим образом. Linq разработан для оптимистичного параллелизма; Обычно, когда вам нужно применить ограничение UNIQUE в вашем приложении, вы ждете, пока изменения действительно будут сохранены, и затем обрабатываете нарушение ограничения, если это произойдет. Если вы хотите сделать это немедленно, ваша задача усложняется, что и является причиной многословия и общей глупости.

Еще раз - я рекомендую против дополнительный шаг создания оболочки только для чтения; В любом случае, я добавил код на случай, если ваша спецификация по какой-то причине этого требует.

0 голосов
/ 23 декабря 2009

Это зависает, потому что OnaliasChanging срабатывает во время инициализации, поэтому ваше вспомогательное поле (псевдоним) никогда не инициализируется, поэтому оно всегда равно нулю?

Без лишнего контекста, вот как это звучит для меня.

...