Я пытаюсь решить дилемму, которая мучила меня последние несколько месяцев.
Мои коллеги и я полностью не согласны с технической проблемой, и я хотел бы услышать мнение нашего любимого сообщества по этому вопросу.
В двух словах:
Желательно ли использовать перечисления (с потенциально возможными атрибутами, такими как «Описание») или использовать сущности (со свойствами «Имя» и «Описание»)?
Подробнее:
В нашей модели предметной области у нас есть множество мини-сущностей, которые содержат только Id, Name и Description.
Описание в 95% случаев соответствует названию.
Для объяснения я собираюсь привести один из множества примеров: в нашем объекте Security у нас есть свойство AssetClass.
AssetClass имеет статический список значений («Equity», «Bond» и т. Д.) И не изменяется в интерфейсе или в чем-либо еще.
Проблема в том, что когда вы хотите получить все ценные бумаги с классом активов "Bond", скажем, NHibernate должен будет присоединиться к таблице AssetClass ... и, учитывая, что AssetClass не является единственным таким свойством, вы Можно представить влияние всех этих соединений на производительность.
Наше текущее решение: (с которым я не согласен):
В нашем коде есть несколько жестко запрограммированных экземпляров класса AssetClass со всеми их соответствующими значениями и идентификаторами (т. Е. Эквити с идентификатором 1, связью с идентификатором 2 и т. Д.), Которые соответствуют содержимому базы данных:
public partial class AssetClass
{
static public AssetClass Equity = new AssetClass(1, "Equity", "Equity");
static public AssetClass Bond = new AssetClass(2, "Bond", "Bond");
static public AssetClass Future = new AssetClass(3, "Future", "Future");
static public AssetClass SomethingElse = new AssetClass(4, "Something else", "This is something else");
}
Мы также создали специальный тип NHibernate (код ниже, если вам интересно), который позволяет нам избегать NHibernate делать соединение, загружая этот жестко запрограммированный экземпляр вместо того, чтобы идти в базу данных, чтобы получить его:
using System;
using System.Data;
using System.Data.Common;
using NHibernate.Dialect;
using NHibernate.SqlTypes;
using NHibernate.Type;
namespace MyCompany.Utilities.DomainObjects
{
public abstract class PrimitiveTypeBase<T> : PrimitiveType where T : class, IUniquelyNamed, IIdentifiable
{
private readonly PrimitiveTypeFactory<T> _factory;
public PrimitiveTypeBase() : base(SqlTypeFactory.Int32)
{
_factory = new PrimitiveTypeFactory<T>();
}
public override string Name
{
get { return typeof(T).Name; }
}
public override Type ReturnedClass
{
get { return typeof(T); }
}
public override Type PrimitiveClass
{
get { return typeof (int); }
}
public override object DefaultValue
{
get { return null; }
}
public override void Set(IDbCommand cmd, object value, int index)
{
var type = value as T;
var param = cmd.Parameters[index] as DbParameter;
param.Value = type.Id;
}
public override object Get(IDataReader rs, int index)
{
return GetStaticValue(rs[index]);
}
public override object Get(IDataReader rs, string name)
{
return GetStaticValue(rs[name]);
}
private T GetStaticValue(object val)
{
if (val == null)
{
return (T)DefaultValue;
}
int id = int.Parse(val.ToString());
T entity = _factory.GetById(id); // that returns, by reflection and based on the type T, the static value with the given Id
if (entity == null)
{
throw new InvalidOperationException(string.Format("Could not determine {0} for id {1}", typeof (T).Name, id));
}
return entity;
}
public override object FromStringValue(string xml)
{
return GetStaticValue(xml);
}
public override string ObjectToSQLString(object value, Dialect dialect)
{
var type = value as T;
return type.Id.ToString();
}
}
}
Мое решение: (с которым я согласен: -))
Замена этих сущностей перечислениями, и если нам когда-либо понадобится поле Description, используйте атрибут.
У нас также может быть ограничение на базу данных, чтобы вы не могли хранить случайные значения, которые не соответствуют перечислению.
Их рациональное использование перечислений:
- Это не объект, поэтому вы не можете расширить его, это не объектно-ориентированное и т. Д.
- Вы не можете легко получить описание или иметь «правильные английские» имена (с пробелами или символами), такие как «My Value» (которое в перечислении будет «MyValue»)
- Enums sucks
- Атрибут отстой
Мое рациональное против нашего нынешнего решения:
- У нас может быть несоответствие между идентификаторами в коде и тем, что находится в базе данных
- Поддерживать его намного сложнее (мы должны быть абсолютно уверены, что все имеющиеся у нас жестко закодированные значения также присутствуют в базе данных)
- Атрибуты и перечисления не сосут при правильном использовании и для статических значений, подобных этим
- Для «правильных английских» имен мы также можем использовать атрибут с некоторым методом расширения, чтобы использовать его.
Теперь, что ВЫ думаете?