Разобрать Enum с FlagsAtribute для SqlParameter - PullRequest
5 голосов
/ 22 мая 2011

У меня есть атрибут Enum with Flags.

  [Flags]
    public enum AlcoholStatus
    {
        NotRecorded = 1,
        Drinker = 2,
        NonDrinker = 4
    }

Я создаю Sqlparameter, как показано ниже.

new SqlParameter("@AlcoholStatus", SqlDbType.VarChar) {Value = (int) AlcoholStatus}

Если AlcoholStatus имеет все значения (NotRecorded | Drinker | NonDrinker), он возвращает 7 в качестве значения для SqlParameter.

Я анализирую этот параметр для хранимой процедуры, и я предпочитаю, чтобы я мог разобрать значение как «1,2,3». Какой лучший способ сделать это?

Или существует какой-либо другой простой способ фильтрации записей путем анализа целочисленного значения 7 в хранимой процедуре?

РЕДАКТИРОВАТЬ: Это происходит в функциональном фильтре, где пользователь хочет видеть людей с любым из вышеуказанных статусов. Это довольно сложный SQL-запрос. Там я фильтрую AlcoholStatus, как показано ниже

WHERE AlcoholStatus IN "1,2,4,"

Ответы [ 5 ]

8 голосов
/ 22 мая 2011

Оставляя в стороне вопрос о том, имеет ли это перечисление смысл как [Flags], IMO единственный разумный способ хранения этих данных - в столбце int. Просто сохраните значение - больше ничего не требуется. Попытка вызвать это как varchar - ошибка. Задача БД - хранить данные , а не заботиться о представлении.

Если вам нужно выполнить фильтрацию по этому, вы можете использовать побитовые операторы в поиске, но учтите, что на производительность это влияет, так как при поиске по комбинации (а не по равенству, которое может использовать некластеризованный индекс). Если вам нужно выполнить поиск по произвольным комбинациям , вместо этого рассмотрите возможность денормализации. Если вам нужно искать только по предсказуемым битам , вы можете поднять их с вычисленным постоянным индексированным столбцом - то есть у вас может быть автоматический столбец IsDrinker (bit), представляющий бит 2.

2 голосов
/ 22 мая 2011

Вы можете передать 7 хранимой процедуре и попрощаться с любыми преимуществами, которые вы можете получить от индекса в столбце AlcoholStatus, если вы начнете значения AND в предложении WHERE.

Нечто похожее на приведенное ниже может быть тем, что вам нужно, если вам нужно создать строку идентификаторов. При необходимости оптимизируйте - я не учел, что в вашем перечислении есть только три флага, например.

Вам также следует остерегаться внедрения SQL-кода, если при построении операторов вы возитесь со строками в SQL-коде.

string values = "";
for(int i = 0; i < 30; ++i) {
  if((((int)AlcoholStatus) & (1 << i)) != 0) {
    if(values != "") {
      values += ",";
    }

    values += (i + 1).ToString();
  }
}
1 голос
/ 22 мая 2011

Заранее, я очень мало знаю о сиквел-сервере ... но ...

Вы имели в виду proprty new SqlParameter("@AlcoholStatus", SqlDbType.VarChar) {Value = (int) client.AlcoholStatus} воображаемого класса "Client" (вместо enum type AlcoholStatus)?

Также я склонен думать, что поле "Binary Flags" будет "естественно" храниться в целочисленном поле ... и, возможно, в этом случае без знака.VarChar просто кажется странным выбором.

0 голосов
/ 28 мая 2011

Я написал метод ниже, чтобы получить разделенные запятыми идентификаторы перечисления для анализа их в базе данных.

private static string GetAlcoholStatuses(Enums.Enums.AlcoholStatus? alcoholStatus)
{
    if (alcoholStatus == null)
        return string.Empty;

    Enums.Enums.AlcoholStatus alcoholStatusValue = alcoholStatus.Value;
    string alcoholStatuses = string.Empty;

    if (alcoholStatusValue.HasFlag(Enums.Enums.AlcoholStatus.Drinker))
    {
        alcoholStatuses = string.Format("{0}{1}{2}", alcoholStatuses, (int)Enums.Enums.AlcoholStatus.Drinker, ",");
    }
    if (alcoholStatusValue.HasFlag(Enums.Enums.AlcoholStatus.NonDrinker))
    {
        alcoholStatuses = string.Format("{0}{1}{2}", alcoholStatuses, (int)Enums.Enums.AlcoholStatus.NonDrinker, ",");
    }
    if (alcoholStatusValue.HasFlag(Enums.Enums.AlcoholStatus.NotRecorded))
    {
        alcoholStatuses = string.Format("{0}{1}{2}", alcoholStatuses, (int)Enums.Enums.AlcoholStatus.NotRecorded, ",");
    }

    return alcoholStatuses;
}
0 голосов
/ 22 мая 2011

Если я правильно понимаю, вы пытаетесь отфильтровать для определенных сценариев, например, вы можете использовать побитовые операции для вашего где, например, SELECT * FROM MyTable WHERE AlcoholStatus & 0x3 выберет Not Recorded и Drinker одновременно. Вы также можете собрать хранимую процедуру, которая преобразует AlcoholStatus в строку типа 1,2,3, используя серию CASE WHEN.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...