Создать объект из строки базы данных

Допустим, я создаю уровень доступа к данным для приложения. Обычно у меня есть определение класса для каждого типа объекта, который хранится в базе данных. Конечно, при фактическом доступе к данным извлекаются данные в форме носителя данных, типизированного или нетипизированного набора данных или подобного, обычно с данными, необходимыми для создания одного объекта для каждой строки результатов.

Как вы подойдете к созданию экземпляров объектов на уровне данных? Будет ли конструктор, принимающий строку данных? Если да, то как сделать этот тип безопасным? Или у вас должен быть список в конструкторе по одному параметру для каждого поля, которое вы хотите создать, даже если полей может быть много? Вы бы отметили этот конструктор как «внутренний»?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
4
0
2 356
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Если вас не устраивают DataRow или SqlDataReader, вам следует взглянуть на систему ORM, такую ​​как Linq to Sql или nHibernate, вместо того, чтобы заново изобретать колесо самостоятельно.

(Кстати, это называется паттерн "ActiveRecord")

Ответ принят как подходящий

Я настоятельно рекомендую вам использовать инструмент ORM. Даже простые проекты могут использовать ORM быстро и незаметно ... в частности, обратите внимание на инструмент ActiveRecordзамок (который находится поверх NHibernate для упрощения объявления модели).

Я добился этого с помощью отражения. Я называю столбец из оператора Select объекта.

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

Это пример:

private T ObjectFromRow(DataRow row)
{
    Type t = typeof(T);

    T newObj = (T)Activator.CreateInstance(t);


    System.Reflection.PropertyInfo[] properties = t.GetProperties();

    for (int i = 0; i < properties.Length; i++)
    {
        if (!properties[i].CanWrite)
        {
            continue;
        }

        if (!row.Table.Columns.Contains(properties[i].Name))
        {
            continue;
        }

        if (row[properties[i].Name] == DBNull.Value)
        {
            continue;
        }

        if (properties[i].PropertyType == typeof(string))
        {
            properties[i].SetValue(newObj, row[properties[i].Name], null);
        }
        else if (properties[i].PropertyType == typeof(double))
        {
            properties[i].SetValue(newObj, double.Parse(row[properties[i].Name].ToString()), null);
        }
        else if (properties[i].PropertyType == typeof(int))
        {
            properties[i].SetValue(newObj, int.Parse(row[properties[i].Name].ToString()), null);
        }
        else if (properties[i].PropertyType == typeof(DateTime))
        {
            properties[i].SetValue(newObj, DateTime.Parse(row[properties[i].Name].ToString()), null);
        }
        else if (properties[i].PropertyType == typeof(bool))
        {
            properties[i].SetValue(newObj, bool.Parse(row[properties[i].Name].ToString()), null);
        }
    }

    return newObj;
}

@Joel (re: сложные запросы, соединения и т. д.)

Инструмент NHibernate и Castle ActiveRecord может обрабатывать очень сложные запросы и объединения через отношения классов и тщательный класс «Expression» (который вы можете добавить к методам запроса) или использование «языка запросов Hibernate» (HQL).

Вы можете погуглить любую из этих деталей, проверить официальный документация или посмотреть потрясающие скринкасты Лето NHibernate.

В качестве альтернативы NHibernate & Castle вы можете взглянуть на SubSonic. Здесь также используется ActiveRecord, но он больше похож на швейцарский армейский нож, чем на NHibernate.

Обновлено:

Вот образец из документации SubSonic:

Simple Select with string columns

            int records = new Select("productID").
                 From("Products").GetRecordCount();

            Assert.IsTrue(records == 77);

Simple Select with typed columns

            int records = new Select(Product.ProductIDColumn, Product.ProductNameColumn).
                From<Product>().GetRecordCount();
            Assert.IsTrue(records == 77);

И еще немного Примеры:

Standard Deviation

    const double expected = 42.7698669325723;

    // overload #1
    double result = new
        Select(Aggregate.StandardDeviation("UnitPrice"))
        .From(Product.Schema)
        .ExecuteScalar<double>();
    Assert.AreEqual(expected, result);

    // overload #2
    result = new
        Select(Aggregate.StandardDeviation(Product.UnitPriceColumn))
        .From(Product.Schema)
        .ExecuteScalar<double>();
    Assert.AreEqual(expected, result);

    // overload #3
    result = new
        Select(Aggregate.StandardDeviation("UnitPrice", "CheapestProduct"))
        .From(Product.Schema)
        .ExecuteScalar<double>();
    Assert.AreEqual(expected, result);

    // overload #4
    result = new
        Select(Aggregate.StandardDeviation(Product.UnitPriceColumn, "CheapestProduct"))
        .From(Product.Schema)
        .ExecuteScalar<double>();
    Assert.AreEqual(expected, result);

И немного Методы с подстановочными знаками:

 [Test]
        public void Select_Using_StartsWith_C_ShouldReturn_9_Records() {


            int records = new Select().From<Product>()
                .Where(Northwind.Product.ProductNameColumn).StartsWith("c")
                .GetRecordCount();
            Assert.AreEqual(9, records);
        }

Другие вопросы по теме