Таблица базы данных Delphi map как класс - PullRequest
4 голосов
/ 21 сентября 2011

Мой друг спросил меня, как он может во время выполнения создать класс для «сопоставления» таблицы базы данных.Он использует ADO для подключения к базе данных.

Мой ответ состоял в том, что он может заполнить ADOQuery «выбрать первую строку из table_name», установить соединение с базой данных, открыть запрос и после этого, используя цикл в полях ADOQuery.Field, которые он может получить.FieldName и FieldType всех полей из таблицы.Таким образом, он может иметь все поля таблицы и их тип в качестве членов класса.

Есть другие варианты решения его проблемы?

Ответы [ 5 ]

6 голосов
/ 21 сентября 2011

@ RBA, один из способов - определить свойства класса, который вы хотите отобразить как «опубликованный», затем использовать RTTI для циклического перемещения по свойствам и присвоения строк набора данных каждому свойству.

Пример:

TMyClass = class
private
  FName: string;
  FAge: Integer;
published
  property Name: string read FName write FName;
  property Age: Integer read FAge write FAge;
end;

Теперь сделайте запрос:

myQuery.Sql.Text := 'select * from customers';
myQuery.Open;
while not myQuery.Eof do
begin
  myInstance := TMyClass.create;
  for I := 0 to myQuery.Fields.Count - 1 do
    SetPropValue(myInstance, myQuery.Fields[I].FieldName, myQuery.Fields[I].Value);
  // now add myInstance to a TObjectList, for example
  myObjectList.Add(myInstance);  
  Next;
end;

Этот простой пример работает, только если все поля, возвращаемые запросом, имеют точное совпадение в классе.

Более совершенный пример (до вас) должен сначала получить список свойств в классе, а затем проверить, существует ли возвращенное поле в классе.

Надеюсь, это поможет, Leonardo.

3 голосов
/ 22 сентября 2011

Не настоящий класс, но нечто очень похожее.Некоторое время назад я написал блог о решении, которое может соответствовать вашим потребностям здесь.Он использует вызываемый пользовательский вариант для сопоставления полей, который позволяет получить доступ к полям, таким как свойства класса.

Справку Delphi можно найти здесь , а запись в блоге состоит из здесь и здесь .Исходный код можно найти в CodeCentral 25386

2 голосов
/ 21 сентября 2011

Инструменты генерации кода, такие как те, которые используются в решениях O / RM, могут создавать классы для вас (их называют многими вещами, но я называю их моделями).

Не совсем понятно, что вам нужно (прочитав также ваши комментарии), но вы можете использовать эти инструменты для создания чего угодно, а не только моделей.Вы можете создавать классы, которые содержат списки ассоциаций полей / свойств или флаги схемы базы данных, такие как «Поле X <-> Флаг первичного ключа» и т. Д.

Некоторые из них уже есть, но если выВы можете построить весь O / RM самостоятельно, вы можете (я сделал).Но это гораздо больший вопрос :) Обычно он включает добавление кода, который знает, как запрашивать, вставлять, удалять и обновлять ваши модели в базе данных (так называемые методы CRUD).Это не сложно, но тогда вы лишаете себя возможности интегрироваться с элементами управления данными Delphi, и вам нужно будет найти решение для этого.Хотя вам не нужно генерировать методы CRUD, поддержка CRUD необходима для того, чтобы полностью исключить необходимость ручных изменений для последующей адаптации к изменениям схемы базы данных.

В одном из ваших комментариев указано, что вы хотите создать какую-то схемуЗапросы без использования подключения к базе данных.Это правильно?Я делаю это в своих моделях, украшая их атрибутами, которые я могу запрашивать во время выполнения.Для этого требуется Delphi 2010 и его новый RTTI.Например:

[TPrimaryKey]
[TField('EmployeeID', TFieldType.Integer)]
property EmployeeID: integer read GetEmployeeID write SetEmployeeID;

Используя RTTI, я могу взять экземпляр модели и спросить, какое поле представляет первичный ключ, ища тот, который имеет атрибут TPrimaryKeyAttribute.Использование атрибута TField выше обеспечивает связь между свойством и полем базы данных, где они не обязательно должны иметь одинаковые имена.Он может даже предоставить класс преобразования в качестве параметра, так что они не должны иметь одинаковый тип.Есть много возможностей.

Я использую MyGeneration и пишу свои собственные шаблоны для этого.Это просто и открывает целый мир возможностей для вас, даже за пределами O / RM.

MyGeneration (бесплатный инструмент генерации кода) http://www.mygenerationsoftware.com/ http://sourceforge.net/projects/mygeneration/

Учебник MyGeneration (мой блог) http://interactiveasp.net/blogs/spgilmore/archive/2009/12/03/getting-started-with-mygeneration-a-primer-and-tutorial.aspx

Я потратил около 15 минут, чтобы написать скрипт MyGeneration, который делает то, что вы хотите.Вам нужно будет определить ваши типы Delphi для базы данных, которую вы используете в XML, но этот скрипт сделает все остальное.Я не тестировал его, и он, вероятно, захочет его расширить, но он даст вам представление о том, с чем вы столкнулись.

<%# reference assembly = "System.Text"%><%

public class GeneratedTemplate : DotNetScriptTemplate
{
    public GeneratedTemplate(ZeusContext context) : base(context) {}

    private string Tab()
    {
        return Tab(1);
    }

    private string Tab(int tabCount)
    {
        System.Text.StringBuilder sb = new System.Text.StringBuilder();
        for (int j = 0; j < 1; j++)
            sb.Append("  ");    // Two spaces
        return sb.ToString();
    }

    //---------------------------------------------------
    // Render() is where you want to write your logic    
    //---------------------------------------------------
    public override void Render()
    {
        IDatabase db = MyMeta.Databases[0];

%>unit ModelsUnit;

interface

uses
  SysUtils;

type
<%
        foreach (ITable table in db.Tables)
        {
%>
<%=Tab()%>T<%=table.Name%>Model = class(TObject)
<%=Tab()%>protected
<%          foreach (IColumn col in table.Columns)
            {
%><%=Tab()%><%=Tab()%>f<%=col.Name%>: <%=col.LanguageType%>;
<%          }%>
<%=Tab()%>public
<%          foreach (IColumn col in table.Columns)
            {
%><%=Tab()%><%=Tab()%>property <%=col.Name%>: <%=col.LanguageType%> read f<%=col.Name%> write f<%=col.Name%>;
<%          }%>
<%=Tab()%><%=Tab()%>
<%=Tab()%>end;<%
        }
%>

implementation

end.

<%
    }

}
%>

Вот один из сгенерированных классов таблицпо приведенному выше сценарию:

TLOCATIONModel = class(TObject)
  protected
    fLOCATIONID: integer;
    fCITY: string;
    fPROVINCE: string;

  public
    property LOCATIONID: integer read fLOCATIONID write fLOCATIONID;
    property CITY: string read fCITY write fCITY;
    property PROVINCE: string read fPROVINCE write fPROVINCE;


  end;
2 голосов
/ 21 сентября 2011

Это то, что называется ORM.То есть объектно-реляционное отображение .У вас есть несколько платформ ORM для Delphi.Смотрите, например, этот вопрос .

Конечно, не забудьте взглянуть на наш маленький mORMot для Delphi 6 вплоть до XE2 - он может подключаться к любой базе данных, используя непосредственно OleDB (без уровня ADO) илидругие провайдеры.Доступно много документации (более 600 страниц), включая общие аспекты дизайна и архитектуры.

Например, для mORMot база данных Baby Таблица определена в коде Delphi как:

<i>/// some enumeration</i>
<i>// - will be written as 'Female' or 'Male' in our UI Grid</i>
<i>// - will be stored as its ordinal value, i.e. 0 for sFemale, 1 for sMale</i>
TSex = (sFemale, sMale);<p>
<i>/// table used for the Babies queries</i>
TSQLBaby = <b>class</b>(TSQLRecord)
  <b>private</b>
    fName: RawUTF8;
    fAddress: RawUTF8;
    fBirthDate: TDateTime;
    fSex: TSex;
  <b>published</b>
    <b>property</b> Name: RawUTF8 <b>read</b> fName <b>write</b> fName;
    <b>property</b> Address: RawUTF8 <b>read</b> fAddress <b>write</b> fAddress;
    <b>property</b> BirthDate: TDateTime <b>read</b> fBirthDate <b>write</b> fBirthDate;
    <b>property</b> Sex: TSex <b>read</b> fSex <b>write</b> fSex;
<b>end</b>;

При добавлении этого класса TSQLBaby к экземпляру TSQLModel, общему для клиента и сервера, соответствующая таблица Baby создается платформой Framework в ядре базы данных.Затем объекты становятся доступными как на стороне клиента, так и на стороне сервера, через ссылку RESTful (через HTTP, используя JSON для передачи).Вся работа SQL ('CREATE TABLE ...') выполняется платформой.Просто код на Паскале, и все сделано для вас.Даже необходимые индексы будут созданы ORM.И вы не пропустите ни одного или;в вашем запросе SQL.

Мой совет не начинать писать свой собственный ORM с нуля.

Если вы просто хотите отобразить некоторые таблицы БД с объектами, вы можете сделать это легко.Но чем больше времени вы потратите на это, тем сложнее будет ваше решение, и вы окончательно изобрели колесо!Так что для небольшого приложения это хорошая идея.Для приложения, которое может расти в будущем, рассмотрите возможность использования существующего (и все еще поддерживаемого) ORM.

1 голос
/ 21 сентября 2011

В зависимости от базы данных вы можете запросить таблицы / представления INFORMATION_SCHEMA, что вам нужно. Я сделал это в архитектуре, которую я создал и до сих пор использую в приложениях БД. При первом подключении к базе данных он запрашивает информацию типа «словарь данных» и сохраняет ее для использования приложением.

...