Generics и база данных - проблема дизайна - PullRequest
5 голосов
/ 26 августа 2011

Ситуация такова, что у меня есть таблица, которая моделирует сущность. Эта сущность имеет ряд свойств (каждое из которых идентифицируется столбцом в таблице). Дело в том, что в будущем мне нужно будет добавить новые свойства или удалить некоторые свойства. Проблема состоит в том, как смоделировать базу данных и соответствующий код (используя C #), чтобы при возникновении такого случая было бы очень просто просто «иметь» новое свойство.

В начале было только одно свойство, поэтому у меня был один столбец. Я определил соответствующее свойство в классе с соответствующим типом и именем, затем создал хранимые процедуры для его чтения и обновления. Затем появилось второе свойство, быстро вставленное копированием, изменившее имя и тип и немного SQL, и вот оно. Очевидно, что это не подходящая модель в будущем. К этому времени некоторые из вас могут предложить ORM (EF или другой), потому что это автоматически сгенерирует SQL и код, но сейчас это не вариант для меня.

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

Мне бы хотелось иметь решение, которое "максимально строго набрано", поэтому мне не нужно выполнять много типов приведения и разбора. Я бы определил доступные свойства в коде, чтобы вы не угадали, что у вас есть, и использовали магические строки и тому подобное. Тогда процесс добавления нового свойства в систему будет означать только добавление нового столбца в таблицу и добавление нового свойства «определение» в коде (например, в перечислении).

Ответы [ 2 ]

2 голосов
/ 26 августа 2011

Похоже, вы хотите сделать это:

MyObj x = new MyObj();
x.SomeProperty = 10;

У вас есть таблица, созданная для этого, но вы не хотите продолжать изменять эту таблицу, когда добавляете

x.AnotherProperty = "Some String";

Вам необходимо нормализовать данные таблицы следующим образом:

-> BaseTable
   RecordId, Col1, Col2, Col3

-> BaseTableProperty
   PropertyId, Name

-> BaseTableValue
   ValueId, RecordId, PropertyId, Value

Ваш класс будет выглядеть так:

 public class MyObj
 {
      public int Id { get; set; }
      public int SomeProperty { get; set; }
      public string AnotherProperty { get; set; }
 }

Когда вы создаете свой объект из вашего DL, вы перечисляете набор записей. Затем вы один раз пишете код, который проверяет свойство с тем же именем, что и ваша конфигурация (BaseTableProperty.Name == MyObj.<PropertyName>), а затем пытаетесь привести тип к этому типу при перечислении набора записей.

Затем вы просто добавляете другое свойство к вашему объекту, другую запись в базу данных в BaseTableProperty, и затем вы можете хранить значения для этого парня в BaseTableValue.

Пример: * * один тысяча двадцать-одна

 RecordId
 ========
 1

 PropertyId          Name
 ==========          ====
 1                   SomeProperty

 ValueId     RecordId       PropertyId      Value
 =======     ========       ==========      =====
 1           1              1               100

У вас есть два набора результатов: один для базовых данных, а другой - из таблиц свойств и значений. Перечисляя каждую запись, вы видите Имя SomeProperty - существует ли typeof(MyObj).GetProperty("SomeProperty")? Да? Какой это тип данных? Int? Хорошо, тогда попробуйте преобразовать «100» в int, установив свойство:

 propertyInfo.SetValue(myNewObjInstance, Convert.ChangeType(dbValue, propertyInfo.PropertyType), null);

Для каждого свойства.

0 голосов
/ 26 августа 2011

Даже если вы сказали, что не можете их использовать, это то, что делает большинство ORM. В зависимости от того, какой из них вы используете (или даже создаете, если это опыт обучения), они будут сильно различаться по сложности и производительности. Если вы предпочитаете легкий вес ORM, отметьте Dapper.Net . Он также использует дженерики, поэтому вы можете проверить код, посмотреть, как он работает, и создать собственное решение, если это необходимо.

...