USE [master] GO CREATE DATABASE [TestRtti] GO USE [TestRtti] GO CREATE TABLE [dbo].[Users_Persons]( [Guid] [uniqueidentifier] ROWGUIDCOL NOT NULL CONSTRAINT [DF_Users_Persons_Guid] DEFAULT (newid()), [Created] [datetime2](7) NOT NULL CONSTRAINT [DF_Users_Persons_Created] DEFAULT (getutcdate()), [Written] [datetime2](7) NOT NULL CONSTRAINT [DF_Users_Persons_Written] DEFAULT (getutcdate()), [First_Name] [nvarchar](30) NOT NULL, [Middle_Name] [nvarchar](30) NOT NULL, [Last_Name] [nvarchar](30) NOT NULL, [Sex] [bit] NOT NULL, [Born] [date] NULL ) ON [PRIMARY] GO ALTER TABLE [dbo].[Users_Persons] ADD CONSTRAINT [PK_Users_Persons] PRIMARY KEY NONCLUSTERED ( [Guid] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] GO INSERT [dbo].[Users_Persons] ([Guid], [Created], [Written], [First_Name], [Middle_Name], [Last_Name], [Sex], [Born]) VALUES (N'291fefb5-2d4e-4ccf-8ca0-25e97fabefff', CAST(N'2016-07-21 10:56:16.6630000' AS DateTime2), CAST(N'2016-12-09 16:22:01.8670000' AS DateTime2), N'', N'', N'', 1, CAST(N'1970-01-01' AS Date)) GO INSERT [dbo].[Users_Persons] ([Guid], [Created], [Written], [First_Name], [Middle_Name], [Last_Name], [Sex], [Born]) VALUES (N'11ad8670-158c-4777-a099-172acd61cbd3', CAST(N'2016-07-21 10:59:02.2030000' AS DateTime2), CAST(N'2016-12-09 16:22:10.4730000' AS DateTime2), N'', N'', N'', 1, CAST(N'1970-01-01' AS Date)) GO
unit UsersPersonsEntity; interface uses Generics.Collections, DataSetReader; type TUsersPersonsEntity = class(TBaseDataRecord) private FGuid: TGUID; FCreated: TDateTime; FWritten: TDateTime; FFirstName: String; FMiddleName: String; FLastName: String; FSex: Boolean; FBorn: TDate; public property Guid: TGUID read FGuid write FGuid; property Created: TDateTime read FCreated write FCreated; property Written: TDateTime read FWritten write FWritten; property First_Name: String read FFirstName write FFirstName; property Middle_Name: String read FMiddleName write FMiddleName; property Last_Name: String read FLastName write FLastName; property Sex: Boolean read FSex write FSex; property Born: TDate read FBorn write FBorn; end; TUsersPersonsList = TDataRecordsList<TUsersPersonsEntity>; TUsersPersonsReader = TDataReader<TUsersPersonsEntity>; implementation end.
unit DataSetReader; interface uses System.TypInfo, System.Rtti, SysUtils, DB, Generics.Collections, Generics.Defaults; type TBaseDataRecord = class public constructor Create; overload; virtual; procedure SetPropertyValueByField(ClassProperty: TRttiProperty; Field: TField; FieldValue: Variant); procedure SetRowValuesByFieldName(DataSet: TDataSet); procedure AfterRead; virtual; end; TBaseDataRecordClass = class of TBaseDataRecord; TDataRecordsList<T: TBaseDataRecord> = class(TObjectList<T>); TDataReader<T: TBaseDataRecord, constructor> = class public function Read(DataSet: TDataSet; ListInstance: TDataRecordsList<T> = nil; EntityClass: TBaseDataRecordClass = nil): TDataRecordsList<T>; end; implementation var Context: TRttiContext; { TBaseDataRecord } constructor TBaseDataRecord.Create; begin end; procedure TBaseDataRecord.AfterRead; begin end; procedure TBaseDataRecord.SetPropertyValueByField(ClassProperty: TRttiProperty; Field: TField; FieldValue: Variant); function GetValueGuidFromMsSql: TValue; var Guid: TGUID; begin if Field.IsNull then Guid := TGUID.Empty else Guid := StringToGUID(Field.AsString); Result := TValue.From(Guid); end; var Value: TValue; GuidTypeInfo: PTypeInfo; begin if Field = nil then Exit; GuidTypeInfo := TypeInfo(TGUID); Value := ClassProperty.GetValue(Self); case Field.DataType of ftGuid: begin if Value.TypeInfo = GuidTypeInfo then ClassProperty.SetValue(Self, GetValueGuidFromMsSql) else ClassProperty.SetValue(Self, TValue.FromVariant(FieldValue)); end; else ClassProperty.SetValue(Self, TValue.FromVariant(FieldValue)); end; end; procedure TBaseDataRecord.SetRowValuesByFieldName(DataSet: TDataSet); var Field: TField; FieldName: String; FieldValue: Variant; ClassName: String; ClassType: TRttiType; ClassProperty: TRttiProperty; begin ClassName := Self.ClassName; ClassType := Context.GetType(Self.ClassType.ClassInfo); for ClassProperty in ClassType.GetProperties do begin Field := DataSet.FindField(ClassProperty.Name); if Field <> nil then begin FieldName := Field.FieldName; FieldValue := Field.Value; SetPropertyValueByField(ClassProperty, Field, FieldValue); end; end; end; { TDataReader<T> } function TDataReader<T>.Read(DataSet: TDataSet; ListInstance: TDataRecordsList<T>; EntityClass: TBaseDataRecordClass): TDataRecordsList<T>; var Row: T; begin if ListInstance = nil then Result := TDataRecordsList<T>.Create else begin Result := ListInstance; Result.OwnsObjects := True; Result.Clear; end; DataSet.DisableControls; Result.Capacity := DataSet.RecordCount; while not DataSet.Eof do begin if EntityClass = nil then Row := T.Create() else Row := EntityClass.Create() as T; Row.SetRowValuesByFieldName(DataSet); Row.AfterRead; Result.Add(Row); DataSet.Next; end; end; initialization Context := TRttiContext.Create; end.
program TestRtti; {$APPTYPE CONSOLE} {$R *.res} uses DB, ADODB, System.SysUtils, ActiveX, DataSetReader in 'DataSetReader.pas', UsersPersonsEntity in 'UsersPersonsEntity.pas'; var Connection: TADOConnection; Query: TADOQuery; UsersPersons: TUsersPersonsList; UserPerson: TUsersPersonsEntity; Reader: TUsersPersonsReader; i: Integer; begin ReportMemoryLeaksOnShutdown := True; UsersPersons := nil; try CoInitialize(nil); Connection := TADOConnection.Create(nil); try Connection.ConnectionString := 'Provider=SQLNCLI11.1;Integrated Security=SSPI;Persist Security Info=False;User ID="";' + 'Initial Catalog="TestRtti";Data Source=localhost;Initial File Name="";Server SPN=""'; Connection.Connected := True; Query := TADOQuery.Create(nil); Reader := TUsersPersonsReader.Create; try Query.Connection := Connection; Query.SQL.Text := 'SELECT * FROM Users_Persons'; Query.Open; UsersPersons := Reader.Read(Query); Writeln(' : ', UsersPersons.Count); for i := 0 to UsersPersons.Count - 1 do begin UserPerson := UsersPersons[i]; Writeln(Format('%d. %s %s %s %s', [i + 1, UserPerson.First_Name, UserPerson.Middle_Name, UserPerson.Last_Name, FormatDateTime('dd.mm.yyyy', UserPerson.Born)])); end; Writeln(' Enter ...'); Readln; finally Query.Free; Reader.Free; end; finally Connection.Free; if UsersPersons <> nil then FreeAndNil(UsersPersons); end; except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; end.
Source: https://habr.com/ru/post/318318/
All Articles