2013-08-25 2 views
1

Что такое хороший способ обозначить "type" в базе?Лучший способ сохранить тип класса в базе данных?

У меня есть базовый класс Action, который унаследован многочисленными дочерними классами. Action имеет таких членов как Id, Name и т. Д. Все, что соответствует эквивалентным столбцам в таблице в базе данных, называемой action. Так action таблица выглядит следующим образом:

id | name | type 

type столбец обозначает, какое действие она. В моем коде они соответствуют дочерним классам, происходящим от родителя Action. Теперь как сохранить тип класса в поле типа в базе данных?

Тип столбца в db может быть любого типа данных.

Варианты:

  1. Сохранить action.GetType().ToString() в виде строки в БД. И получить тип действия из db обратно, преобразовывая строковое представление типа в его оригинальный тип с использованием отражения. Но это будет проблематично, если имена классов изменятся в будущем.

  2. Создать перечисление для обозначения каждого класса ребенка и украсить его с помощью TypeAttribute, что-то вроде:

    public abstract class Action 
    { 
        public enum Kind 
        { 
         [Type(typeof(ControlAction))] 
         ControlAction = 1, 
    
         [Type(typeof(UpdateAction))] 
         UpdateAction = 2, 
    
         etc 
        } 
    
        public abstract Kind ActionType { get; } 
    } 
    
    public class ControlAction : Action { public override Kind ActionType { get { return Kind.ControlAction; } } } 
    public class UpdateAction : Action { public override Kind ActionType { get { return Kind.UpdateAction; } } } 
    //etc 
    

    Это выглядит хорошо, за исключением того, что для каждого класса здесь и далее я должен создать перечисление , И кажется, что слишком много работы предстоит сделать.

  3. Создайте отдельную статическую хеш-таблицу <int, Type>, которая связывает класс с значением int. Может быть немного нечитаемым.

Есть ли лучшее решение?

+0

Вы пытаетесь создать ОРМ? Или вам действительно нужно (например, для краевого случая) информацию о типе класса, которая должна быть в базе данных, которую можно использовать другими приложениями? – edsioufi

+0

@edsioufi no, это не о orm. Каждое дочернее действие, например 'ControlAction',' UpdateAction' и т. Д. - это действия, созданные клиентами. Каждый тип действия имеет свой собственный набор информации, который будет необходим клиентам. Теперь мне нужен способ сохранить действия, созданные клиентом для базы данных. Позже, когда я загружаю эти различные действия из db, мне нужно выделить «ControlAction» из «UpdateAction». – nawfal

ответ

1

В итоге я использовал вариант 2, но с меньшим количеством помех атрибутов. Что-то вроде этого:

public abstract class Action 
{ 
    public enum Kind 
    { 
     ControlAction = 1, 

     UpdateAction = 2, 

     etc 
    } 

    public abstract Kind ActionType { get; } 
} 

public class ControlAction : Action { public override Kind ActionType { get { return Kind.ControlAction; } } } 
public class UpdateAction : Action { public override Kind ActionType { get { return Kind.UpdateAction; } } } 

Самое большое преимущество этого заключается в том, что (даже если это означает больше печатать), он навязывает числовое значение, которое будет связано с типом класса.

Теперь класс Int просто:

var value = (int)instance.ActionType; 

Очень быстро.

Но для преобразования int в экземпляр класса (или тип класса) мне нужно будет создать экземпляр каждого типа субопераций и сравнить его свойство ActionType в соответствии со значением ввода int. Это будет медленным. Но я могу кэшировать кое-что и делать это быстрее. Что-то вроде:

static readonly Dictionary<Action.Kind, Type> actionTypes = 
    GetDefaultInstanceOfAllActions().ToDictionary(x => x.ActionType, x => x.GetType()); 
public static Action ToAction(this Action.Kind value) 
{ 
    return (Action)Activator.CreateInstance(actionTypes[value]); 
} 

GetDefaultInstanceOfAllActions делает некоторые размышления (один раз), чтобы получить все типы действий (я использую что-то вроде this answer для этого).Я могу даже сделать сделать конкретизации быстрее going the expression route.

Польза:

  1. Меньше хлопот при создании нового класса (атрибуты).

  2. Обеспечивает привязку int к типу класса.

  3. Умеренно быстрый с адекватным кешированием.

2

Я бы выбрал 3-е решение с хеш-таблицей, так как он кажется более чистым. И я бы делегировал его управление в базу данных!

В конце концов, разве это не то, что реляционные базы данных превосходят в наибольшей степени, создавая отношения между двумя объектами (в вашем случае, действием и типом)? Другим преимуществом является то, что вы закончили с нормализованной схемой (конечно, до сих пор в таблице типов есть только один столбец, а именно его имя, но нормализация позволяет легко добавлять дополнительные атрибуты к типам, если они вам понадобятся в будущем, поэтому он чище, чем дизайн).

Схема будет что-то вроде этого:

таблица Действие

action_id(PK) | name | type_id (int, FK to Type table) 

Тип таблицы

type_id(PK) | type_name 

Теперь вы в безопасности, если имя класса изменений будущее (беспокойство от вашего первого предложения со строковым типом). Действительно, все, что вы сделали бы, это изменить значение type_name в соответствующей строке таблицы Type, и все ваши строки Action по-прежнему будут связаны с этой строкой type_id, которые никогда не изменений после создания (здесь нет проблем, так как он не выполняется любое «деловое значение»).

И у вас есть таблица хэша от 3 (таблица Type) в читаемом формате, так как ответственность RDMBS заключается в управлении ключами хэш-таблицы (type_id ПК).

Обратите внимание, что вам не придется связать свой класс к int значения, соответствующего type_id столбца, а выборки из Type стола type_id, посмотрев его против типа класса (type_name).

+2

И чтобы добавить, используйте строки как ActionType, проверьте таблицу Type, если actionType уже существует и вместо этого использует идентификатор (если нет, добавьте его в таблицу типов), вы можете создать что-то вроде кеша (словарь для кэширования типа действия имена с идентификаторами) –

+0

@edsioufi, я не уверен, как это помогает при изменении имени класса. Что следует вводить в 'type_name' в таблице типов? Джероун прекрасно понимает, что ты имел в виду? – nawfal

+0

Нет, кажется, после вашего редактирования. Как выполнить поиск типа в таблице типов? Если 'type_name' является просто строковым представлением' Type' класса, то это не сработает. – nawfal

0

Я бы пошел с вашим первым вариантом и использовал отражение. Скорее всего, вам захочется добавить новые типы действий, а не изменять существующие имена классов, и поэтому удобство сериализации типа с использованием отражения более полезна. Тогда вы можете просто иметь класс утилиты для сериализации действий и восстановления их из их строки типа.

+0

имена классов могут измениться. Я не отвечаю за это. Будущие разработчики не должны быть застигнуты врасплох. Также я не сериализую. – nawfal

Смежные вопросы