Rsdn.Framework.DataAccess
От: IT Россия linq2db.com
Дата: 10.10.05 02:58
Оценка: 64 (9)
Слой доступа к данным (Data Access Layer) является одним из важнейших компонентов любой системы, предназначенный для изоляции источника данных от остальных частей приложения и позволяющий сконцентрировать всё общение с базой данных в одном месте. Задача DAL – считать данные из БД, создать на основе этих данных объект или группу объектов и передать их приложению. Либо наоборот, получить данные от приложения, перевести их в термины базы данных и сохранить. Ничего другого от DAL не требуется. Но зачастую и эта задача не является тривиальной. И не столько из-за своей сложности (как раз ничего сложного в DAL нет), сколько из-за необходимости аккуратно повторять одни и те же рутинные действия каждый раз.

Собственно говоря, основная задача RFD в целом и Rsdn.Framework.DataAccess в частности как раз заключается в том, чтобы свести к минимуму усилия на разработку слоя доступа к данным.

Набор классов предоставляемых рассматриваемым пространством имён предоставляет следующие сервисы:


Класс DataAccessorBase предлагает два набора базовых CRUDL (Create, Read, Update, Delete, List) операций. Первая группа операций работает с сохранёнными процедурами, вторая генерирует в процессе своей работы SQL выражения.

Для работы с сохранёнными процедурами используется следующий список методов: SelectByKey, SelectAll, Insert, Update, DeleteByKey, Delete. Данные методы, там, где это необходимо, приминают в качестве одного из параметров тип объекта, который используется для построения имени сохранённой процедуры.

public object SelectByKey(DbManager db, Type type, params object[] key)
{
  return db
    .SetSpCommand(GetSpName(type, "SelectByKey"), key)
    .ExecuteObject(type);
}

где строковая константа “SelectByKey” является названием действия (action).

Имя сохранённой процедуры может быть задано с помощью специального атрибута ActionSprocName применяемого непосредственно к передаваемому типу. Например, процедура добавления записи в таблицу Employee может быть задана следующим образом:

[ActionSprocName("Insert", "InsertEmployee")]
public class Employee
{
  // ...
}

Если данный атрибут для указанного действия не задан, то в результате вызывается следующий метод, который задаёт правило формирования имени процедуры по умолчанию:

protected virtual string GetDefaultSpName(string typeName, string actionName)
{
  return typeName == null?
    actionName:
    string.Format("{0}_{1}", typeName, actionName);
}

Так для класса Employee имя сохранённой процедуры по умолчанию будет выглядеть следующим образом – "Employee_Insert". Естественно, вы можете перекрыть данный метод и задать своё правило для именования в соответствии со своими соглашениями.

Для работы с базой данных посредством SQL выражений служит второй набор методов, который аналогичен первому за исключением лишь того, что к каждому методу добавляется суффикс Sql: SelectByKeySql, SelectAllSql, InsertSql, UpdateSql, DeleteByKeySql, DeleteSql.

Каждый из этих методов в зависимости от действия и типа объекта формирует текст SQL выражения и при необходимости формирует список параметров:

public object SelectByKeySql(DbManager db, Type type, params object[] key)
{
  return db
    .SetCommand(
      GetSqlText(type, "SelectByKey"),
      GetParameters(db, type, key))
    .ExecuteObject(type);
}

Процессом формированием SQL выражения и списка параметров можно управлять с помощью атрибутов.

[TableName("Employees")]
public abstract class Employee
{
  [MapField("EmployeeID")]
  [PrimaryKey]   public abstract int    ID        { get; }
                 public abstract string LastName  { get; set; }
                 public abstract string FirstName { get; set; }
  [NonUpdatable] public abstract string Notes     { get; set; }
}

По умолчанию в качестве имени таблица используется имя класса. Изменить это поведение можно с помощью атрибута TableName, который применяется к типу объекта как показано выше. Список ключевых полей задаётся с помощью атрибута PrimaryKey. Если какое-либо поле не должно сохраняться при вставке и обновлении записи, то его можно пометить атрибутом NonUpdatable.

Все эти средства необходимы для поддержки базовых команд CRUDL.

Для упрощения работы с написанием кода вызова сохранённых процедур рассматриваемое пространство имён предлагает возможность генерации методов, используя в качестве исходного материала для генерации сигнатуру метода и дополнительные управляющие декларации в виде атрибутов.

Для пояснения работы генератора приведём пример кода обычного метода, использующегося для вызова сохранённой процедуры:

public class EmployeeDataAccessor : DataAccessorBase
{
  public List<Employee> SelectByName(string name)
  {
    using (DbManager db = GetDbManager())
    {
      return db
        .SetSpCommand(GetSpName(typeof(Employee), "SelectByName"),
          .db.Parameter("@name", name))
        .ExecuteList<Employee>();
    }
  }
}

Не трудно заметить, что вся необходимая информация для генерации тела метода у нас уже присутствует в сигнатуре самого метода. Тип возвращаемого значения нам может сказать о том какой из Execute методов необходимо вызывать и какой тип объекта использовать для маппинга. Имя метода вполне можно использовать как имя действия (action), по которому в соответствии с нашими соглашениями будет построено имя сохранённой процедуры. Параметры метода однозначно определяют типы и имена параметров сохранённой процедуры. Т.е. нам вполне достаточно следующего описания метода:

public abstract class EmployeeDataAccessor : DataAccessorBase
{
  public abstract List<Employee> SelectByName(string name);
}

Для генерации классов-аксессоров и создания их экземпляров в Rsdn.Framework.DataAccess входит специальная фабрика классов DataAccessFactory. Создание класса-аксессора с использованием фабрики выглядит следующим образом:

EmployeeDataAccessor da = (EmployeeDataAccessor)DataAccessFactory.CreateInstance(typeof(EmployeeDataAccessor));

либо в варианте для второго фреймворка:

EmployeeDataAccessor da = DataAccessFactory.CreateInstance<EmployeeDataAccessor>();

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

Специально для этой цели служит атрибут ObjectType, который может примеряться либо к конкретному методу, либо к целому классу.
Для непосредственного задания имени сохранённой процедуры служит атрибут SprocName.

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

Тип Execute метода определяется по типу возвращаемого значения. Так для типа DataSet и производных от него будет использоваться метод ExecuteDataSet. Соответственно для типа DataTable и его производных – ExecuteDataTable. Для любого типа, реализующего интерфейс IList, будет подставлен вызов метода ExecuteList. При этом если не заданы соответствующие атрибуты, будет сделана попытка получить тип объекта исходя из типа коллекции. Если тип возвращаемого значения является строкой или value-типом, будет сделан вызов ExecuteNonQuery. Иначе возвращаемый тип считается типом объекта и производится вызов ExecuteObject.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Re: Rsdn.Framework.DataAccess
От: Alexey Axyonov Украина  
Дата: 11.10.05 08:26
Оценка:
Здравствуйте, IT, Вы писали:

IT>Слой доступа к данным (Data Access Layer) является одним из важнейших компонентов любой системы, предназначенный для изоляции источника данных от остальных частей приложения и позволяющий сконцентрировать всё общение с базой данных в одном месте. Задача DAL – считать данные из БД, создать на основе этих данных объект или группу объектов и передать их приложению. Либо наоборот, получить данные от приложения, перевести их в термины базы данных и сохранить. Ничего другого от DAL не требуется. Но зачастую и эта задача не является тривиальной. И не столько из-за своей сложности (как раз ничего сложного в DAL нет), сколько из-за необходимости аккуратно повторять одни и те же рутинные действия каждый раз.


А можно получить точно такое же, только с перламутровыми... тьфу ты, на английском языке?
Я написал тебе письмо, но ответа нет.
... << RSDN@Home 1.2.0 alpha rev. 618>>
Re[2]: Rsdn.Framework.DataAccess
От: IT Россия linq2db.com
Дата: 11.10.05 11:27
Оценка:
Здравствуйте, Alexey Axyonov, Вы писали:

AA>А можно получить точно такое же, только с перламутровыми... тьфу ты, на английском языке?


Только вот это http://rfd.rsdn.ru
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.