Delphi和C++ Builder中的Hibernate开发(五)
Hibernate中Session接口定义了基本的CURD操作:
save()方法把Java对象保存数据库中,update()方法更新数据库中的Java对象,delete()方法把Java对象从数据库中删除,load()方法从数据库中加载Java对象,find()方法从数据库中查询Java对象;
本框架中的Session的CURD操作由TDataOperator类完成。
每一个持久类的实例在数据库中有对应的记录,并拥有一个持久化标识(identifier)。
TDataOperator类的CURD操作的实现分为两种:
第一种从SQL实现持久对象和记录的操作,方法定义如下:
从数据库中的记录加载一个持久对象:
function Load(AType: TTableDataClass; AValue: Variant): TTableData; overload;
保存一个持久对象到数据库中:
function Save(AObject: TTableData): Boolean;
删除一个持久对象对应的数据库表记录:
function Delete(Aobject: TTableData): Boolean; overload;
第二种是用TDataSet的方法实现持久对象和记录的操作,方法定义如下:
从数据库中的记录加载一个持久对象:
function TDataOperator.get(TableName: string; pkName: string; pkValue: variant): TObject;
保存一个持久对象到数据库中:
function TDataOperator.saveData(data: TTableData): Boolean;
删除一个持久对象对应的数据库表记录:
TDataOperator.deleteData(data: TTableData): Boolean;
修改一个持久对象对应的数据库表记录:
function TDataOperator.updateData(data: TTableData): Boolean;
对多个持久对象的成批操作的方法定义有:
function TDataOperator.SaveList(AList: TTableDatalist): Integer;
function TDataOperator.updateAllData(dataList: TTableDatalist): Boolean;
unit UnitDataOperator;
interface
uses
SysUtils, Windows, Messages, Classes, DB, ADODB, Variants, TypInfo, StrUtils,
UnitDataCommand, UnitDataController, UnitAppLogger, UnitBaseTable,
UnitBaseTableList,CnDHibernateBase;
type
TOperateType = (otSelect, otInsert, otUpdate, otDelete);
TDataOperator = class;
TDataOperator = class(TPersistent)
private
FDataController: TDataController;
function AddItemsToList(AList: TTableDatalist; AData: TDataSet): Integer;
function CreateTextCommand(ASQL: string): TDataCommand;
function Execute(ASQL: string; AObject: TTableData): Boolean;
function GetDataSQL(AObject: TTableData;
AOperateType: TOperateType): string;
function GetPreparedCmd(ASQL: string; KeyNames: array of string;
KeyValues: array of variant): TDataCommand; overload;
function GetPreparedCmd(ASQL: string; AObject: TTableData)
: TDataCommand; overload;
function Open(ASQL: string; AObject: TTableData): TDataSet;
public
constructor Create(); reintroduce;
destructor Destroy; override;
class function GetSQLWhere(ANames: array of string): string;
function CheckObjectExists(AType: TTableDataClass;
KeyValue: variant): Boolean;
function FindByKeyValue(AType: TTableDataClass; KeyValue: variant)
: TTableData;
// 加载对象
function Load(AType: TTableDataClass; KeyNames: array of string;
KeyValues: array of variant): TTableData; overload;
function Load(AType: TTableDataClass; AValue: variant): TTableData;
overload;
function LoadAllItems(AList: TTableDatalist;
OnlyEnabled: Boolean = false): Integer;
function LoadItems(AList: TTableDatalist; KeyNames: array of string;
KeyValues: array of variant): Integer;
// 保存对象
function Save(AObject: TTableData): Boolean;
function Delete(AObject: TTableData): Boolean; overload;
{ get one data object }
function get(TableName: string; pkName: string; pkValue: variant): TObject;
{ save or update }
function saveOrUpdate(data: TTableData): Boolean;
function saveData(data: TTableData): Boolean;
{ update }
function updateData(data: TTableData): Boolean;
{ delete }
function deleteData(data: TTableData): Boolean;
{ save or update all }
function saveOrUpdateAllData(dataList: TTableDatalist): Boolean;
function SaveList(AList: TTableDatalist): Integer;
{ update all }
function updateAllData(dataList: TTableDatalist): Boolean;
property DataController: TDataController read FDataController
write FDataController;
end;
const
{$IFDEF DB_ACCESS}
STR_BOOL_VALUE: array [Boolean] of string = ('false', 'true');
{$ELSE}
STR_BOOL_VALUE: array [Boolean] of string = ('0', '1');
{$ENDIF}
implementation
{
******************************** TDataOperator *********************************
}
function TDataOperator.AddItemsToList(AList: TTableDatalist;
AData: TDataSet): Integer;
var
fItem: TTableData;
begin
with AData do
begin
first;
while not Eof do
begin
fItem := AList.ItemType.Create(AData);
// fDataType.Create(Pool, AData);
fItem.IsNew := false;
AList.Add(fItem);
Next;
end; // while
end; // with
result := AData.RecordCount;
end;
function TDataOperator.CheckObjectExists(AType: TTableDataClass;
KeyValue: variant): Boolean;
var
fObj: TTableData;
begin
fObj := FindByKeyValue(AType, KeyValue);
result := fObj <> nil;
// if result then
// fObj.Free;
end;
constructor TDataOperator.Create();
begin
// FDataType := ATableDataType;
// FValueItems := TTableDataList.Create(AOwner, FDataType);
end;
destructor TDataOperator.Destroy;
begin
end;
function TDataOperator.CreateTextCommand(ASQL: string): TDataCommand;
begin
if FDataController = nil then
raise Exception.CreateFmt
('%s.CreateTextCommand:No DataController specified.', [Classname]);
result := TDataCommand.Create(FDataController);
result.CommandText := ASQL;
result.CommandType := cmdText;
end;
function TDataOperator.Delete(AObject: TTableData): Boolean;
var
fSQL: string;
begin
// if not DataController.Connection.InTransaction then
DataController.Connection.BeginTrans;
try
fSQL := GetDataSQL(AObject, otDelete);
result := Execute(fSQL, AObject);
DataController.Connection.CommitTrans;
except
on e: Exception do
begin
DataController.Connection.RollbackTrans;
AppLogger.AddLog(Self, '%s.Delete: %s', [Classname, e.Message]);
raise;
end;
end; // try/except
end;
function TDataOperator.deleteData(data: TTableData): Boolean;
var
map: ICnMap;
hql: string;
begin
map := getPodoProperties(data.TableName, data);
hql := Format(DH_DELETE_RECORD, [data.TableName]) + getSearchEvent(map);
with TADOQuery.Create(nil) do
begin
Connection := Self.DataController.Connection;
SQL.Text := hql;
try
ExecSQL;
result := True;
except
on e: Exception do
begin
result := false;
raise Exception.Create(e.Message);
end;
end;
Free;
end;
end;
function TDataOperator.Execute(ASQL: string; AObject: TTableData): Boolean;
var
fCmd: TADOCommand;
I: Integer;
fParamName: String;
fValue: variant;
begin
result := false;
if FDataController = nil then
raise Exception.CreateFmt
('%s.CreateTextCommand:No DataController specified.', [Classname]);
try
fCmd := TADOCommand.Create(nil);
fCmd.Connection := FDataController.Connection;
fCmd.CommandText := ASQL;
fCmd.CommandType := cmdText;
if AObject <> nil then
begin
for I := 0 to fCmd.Parameters.Count - 1 do // Iterate
begin
fParamName := fCmd.Parameters[I].Name;
try
if AObject.FieldList.IndexOf(fParamName) > -1 then
begin
fValue := AObject.Values[fParamName];
fCmd.Parameters[I].Value := fValue;
end;
except
on e: Exception do
begin
AppLogger.AddLog(Self, 'GetPreparedCmd[ParamName=%s]: %s',
[fParamName, e.Message]);
raise;
end;
end; // try/except
end; // for
end;
// fCmd := Self.GetPreparedCmd(ASQL, AObject);
try
fCmd.Execute;
result := True;
except
on e: Exception do
begin
result := false;
AppLogger.AddLog(Self, 'Execute:%s', [e.Message]);
raise;
end;
end; // try/except
finally
FreeAndNil(fCmd);
end;
end;
function TDataOperator.FindByKeyValue(AType: TTableDataClass; KeyValue: variant)
: TTableData;
begin
// result := FValueItems.FindByKeyValue(KeyValue);
// if result = nil then
result := Load(AType, [AType.KeyColumnName], [KeyValue]);
end;
function TDataOperator.Get(TableName: string; pkName: string;
pkValue: variant): TObject;
var
clazz: TClass;
// obj : TObject;
obj: TObject;
Pplst: PPropList;
Classtypeinfo: PTypeInfo;
classDataInfo: PTypeData;
tempQuery: TADOQuery;
I: Integer;
tk: TTypeKind;
begin
clazz := FindClass(Format(DH_CLASS_NAME, [TableName]));
obj := clazz.NewInstance;
tempQuery := TADOQuery.Create(nil);
with tempQuery do
begin
Connection := Self.DataController.Connection;
SQL.Text := Format(DH_GET_RECORD, [TableName, pkName, pkName]);
Parameters.ParamValues[pkName] := pkValue;
Open;
Classtypeinfo := clazz.ClassInfo;
classDataInfo := GetTypeData(Classtypeinfo);
if classDataInfo.PropCount <> 0 then
begin
GetMem(Pplst, sizeof(PpropInfo) * classDataInfo.PropCount);
try
GetPropInfos(Classtypeinfo, Pplst);
for I := 0 to classDataInfo.PropCount - 1 do
begin
tk := Pplst[I]^.PropType^.Kind;
if tk <> tkMethod then
begin
// set the string properties
if (tk = tkString) or (tk = tkLString) or (tk = tkWString) or
(tk = tkUString) then
begin
SetStrProp((obj as clazz), Pplst[I]^.Name,
FieldByName(Pplst[I]^.Name).AsString);
end;
// set the integer properties
if tk = tkInteger then
begin
try
SetInt64Prop((obj as clazz), Pplst[I]^.Name,
FieldByName(Pplst[I]^.Name).AsInteger);
except
SetInt64Prop((obj as clazz), Pplst[I]^.Name, 0);
end;
end;
// set the float properties
if tk = tkFloat then
begin
try
SetFloatProp((obj as clazz), Pplst[I]^.Name,
FieldByName(Pplst[I]^.Name).AsFloat);
except
SetFloatProp((obj as clazz), Pplst[I]^.Name, 0);
end;
end;
// set the variant properties
if tk = tkVariant then
begin
SetVariantProp((obj as clazz), Pplst[I]^.Name,
FieldByName(Pplst[I]^.Name).Value);
end;
end;
end;
finally
FreeMem(Pplst, sizeof(PpropInfo) * classDataInfo.PropCount);
end;
end;
Close;
Free;
end;
// setFormulaProperties(TableName, pkName, pkValue, obj);
result := obj;
end;
function TDataOperator.GetDataSQL(AObject: TTableData;
AOperateType: TOperateType): string;
const
sSQLType: array [TOperateType] of string = ('select *',
'insert into %s (%s) values (%s)', 'update %s set %s where %s = %s%s',
'delete');
sFieldSplitter = ',';
sParamPrefix = ':';
var
I: Integer;
fNames, fValues: string;
fname: string;
begin
result := EmptyStr;
case AOperateType of //
otSelect, otDelete:
begin
result := Format('%s from %s where %s = %s%s',
[sSQLType[AOperateType], AObject.TableName, AObject.KeyColumnName,
sParamPrefix, AObject.KeyColumnName]);
if (AOperateType = otSelect) and (AObject.OrderByList <> EmptyStr) then
result := result + ' order by ' + AObject.OrderByList;
end;
otInsert:
begin
for I := 0 to AObject.FieldList.Count - 1 do // Iterate
begin
fname := AObject.FieldList[I];
if SameText(AObject.KeyColumnName, fname) and AObject.UseUniqueID and
AObject.AutoKeyValue then
Continue;
fNames := fNames + sFieldSplitter + fname;
end; // for
fValues := StringReplace(fNames, sFieldSplitter,
sFieldSplitter + sParamPrefix, [rfReplaceAll]);
fNames := Copy(fNames, 2, Length(fNames));
fValues := Copy(fValues, 2, Length(fValues));
result := Format(sSQLType[AOperateType], [AObject.TableName, fNames,
fValues]);
end;
otUpdate:
begin
for I := 0 to AObject.FieldList.Count - 1 do // Iterate
begin
fname := AObject.FieldList[I];
if SameText(COL_UNIQUEID, fname) or SameText(AObject.KeyColumnName,
fname) then
Continue;
fNames := fNames + sFieldSplitter + fname + ' = ' +
sParamPrefix + fname;
end; // for
fNames := Copy(fNames, 2, Length(fNames));
result := Format(sSQLType[AOperateType], [AObject.TableName, fNames,
AObject.KeyColumnName, sParamPrefix, AObject.KeyColumnName]);
end;
end; // case
end;
function TDataOperator.GetPreparedCmd(ASQL: string; KeyNames: array of string;
KeyValues: array of variant): TDataCommand;
var
fParam: TParameter;
I: Integer;
begin
result := CreateTextCommand(ASQL);
for I := Low(KeyNames) to High(KeyNames) do // Iterate
begin
fParam := result.Parameters.FindParam(KeyNames[I]);
if fParam <> nil then
begin
fParam.Value := KeyValues[I];
end;
end; // for
end;
function TDataOperator.GetPreparedCmd(ASQL: string; AObject: TTableData)
: TDataCommand;
var
I: Integer;
fParamName: string;
fValue: variant;
begin
// TODO: Prepared the database command and fill the paramlist.
result := CreateTextCommand(ASQL);
if FDataController = nil then
raise Exception.CreateFmt
('%s.CreateTextCommand:No DataController specified.', [Classname]);
result := TDataCommand.Create(FDataController);
result.CommandText := ASQL;
result.CommandType := cmdText;
if AObject <> nil then
begin
for I := 0 to result.Parameters.Count - 1 do // Iterate
begin
fParamName := result.Parameters[I].Name;
try
if AObject.FieldList.IndexOf(fParamName) > -1 then
begin
fValue := AObject.Values[fParamName];
result.Parameters[I].Value := fValue;
end;
except
on e: Exception do
begin
AppLogger.AddLog(Self, 'GetPreparedCmd[ParamName=%s]: %s',
[fParamName, e.Message]);
raise;
end;
end; // try/except
end; // for
end;
end;
class function TDataOperator.GetSQLWhere(ANames: array of string): string;
var
I: Integer;
begin
result := EmptyStr;
for I := Low(ANames) to High(ANames) do // Iterate
begin
result := result + Format(' AND %s = :%s', [ANames[I], ANames[I]]);
end; // for
result := Copy(result, 5, Length(result));
end;
function TDataOperator.Load(AType: TTableDataClass; AValue: variant)
: TTableData;
begin
result := Load(AType, [AType.KeyColumnName], [AValue]);
if result = nil then
begin
AppLogger.AddLog(Self, '%s.Load: Not found [%s=%s]',
[AType.Classname, AType.KeyColumnName, VarToStr(AValue)]);
end;
end;
function TDataOperator.Load(AType: TTableDataClass; KeyNames: array of string;
KeyValues: array of variant): TTableData;
var
fList: TTableDatalist;
begin
result := nil;
fList := TTableDatalist.Create(AType);
try
if LoadItems(fList, KeyNames, KeyValues) > 0 then
begin
result := fList.Items[0] as TTableData;
// result := fList.Extract(fList.Items[0]) as TTableData;
if fList.Count > 1 then
begin
AppLogger.AddLog(Self, '%s.Load: [Count=%d]More than one row found!',
[Classname, fList.Count]);
end;
end;
finally
fList.Free;
end;
// result := FDataType.Create(Pool);
// fSQL := GetDataSQL(result, otSelect);
// fCmd := GetPreparedCmd(fSQL, KeyNames, KeyValues);
end;
function TDataOperator.LoadAllItems(AList: TTableDatalist;
OnlyEnabled: Boolean): Integer;
var
fSQL: string;
fData: TDataSet;
begin
// load all items into AList, return the count.
fSQL := Format('select * from %s', [AList.ItemType.TableName]);
if OnlyEnabled and AList.ItemType.PropertyExists('Enabled') then
fSQL := fSQL + ' where Enabled = ' + STR_BOOL_VALUE[True];
if AList.ItemType.OrderByList <> EmptyStr then
fSQL := fSQL + ' order by ' + AList.ItemType.OrderByList;
fData := Open(fSQL, nil);
try
result := AddItemsToList(AList, fData);
finally
// FreeAndNil(fData);
end;
end;
function TDataOperator.LoadItems(AList: TTableDatalist;
KeyNames: array of string; KeyValues: array of variant): Integer;
var
fCmd: TDataCommand;
fSQL: string;
fData: TDataSet;
fWhere: string;
begin
// load all items into AList, return the count.
result := 0;
fWhere := GetSQLWhere(KeyNames);
fSQL := Format('select * from %s where %s', [AList.ItemType.TableName,
fWhere]);
if AList.ItemType.OrderByList <> EmptyStr then
fSQL := fSQL + ' order by ' + AList.ItemType.OrderByList;
try
try
fCmd := GetPreparedCmd(fSQL, KeyNames, KeyValues);
fData := fCmd.Open;
result := AddItemsToList(AList, fData);
except
on e: Exception do
begin
AppLogger.AddLog(Self, 'LoadItems:%s', [e.Message]);
raise ;
end;
end; // try/except
finally
// FreeAndNil(fData);
FreeAndNil(fCmd);
end;
end;
function TDataOperator.Open(ASQL: string; AObject: TTableData): TDataSet;
var
fCmd: TDataCommand;
begin
fCmd := GetPreparedCmd(ASQL, AObject);
try
result := fCmd.Open;
except
on e: Exception do
begin
AppLogger.AddLog(Self, 'Open:%s', [e.Message]);
raise;
end;
end; // try/except
end;
function TDataOperator.Save(AObject: TTableData): Boolean;
var
fSQL: string;
FIsNew: Boolean;
begin
if AObject.DeleteFlag then
begin
result := Delete(AObject);
Exit;
end;
try
if not DataController.Connected then
DataController.OpenConnection;
DataController.Connection.BeginTrans;
if AObject.IsNew then
fSQL := GetDataSQL(AObject, otInsert)
else
fSQL := GetDataSQL(AObject, otUpdate);
result := Execute(fSQL, AObject);
AObject.IsNew := false;
AObject.Modified := false;
AObject.DeleteFlag := false;
DataController.Connection.CommitTrans;
except
on e: Exception do
begin
DataController.Connection.RollbackTrans;
AppLogger.AddLog(Self, 'Save: %s', [e.Message]);
raise;
end;
end; // try/except
end;
function TDataOperator.saveData(data: TTableData): Boolean;
var
map: ICnMap;
I: Integer;
hql: string;
begin
map := getPodoProperties(data.TableName, data);
hql := Format(DH_SELECT, [data.TableName]);
with TADOQuery.Create(nil) do
begin
Connection := Self.DataController.Connection;;
SQL.Text := hql;
Open;
Append;
// 写入数据
for I := 0 to map.size - 1 do
begin
FieldByName(map.getTable(I).hashName).Value := map.getTable(I).hashValue;
end;
try
Post;
result := True;
except
result := false;
end;
Free;
end;
end;
function TDataOperator.SaveList(AList: TTableDatalist): Integer;
var
I: Integer;
begin
result := 0;
for I := 0 to AList.Count - 1 do // Iterate
begin
if AList[I].DeleteFlag then
Delete(AList[I])
else if (AList[I].Modified or AList[I].IsNew) and Save(AList[I]) then
Inc(result);
end; // for
end;
function TDataOperator.saveOrUpdate(data: TTableData): Boolean;
var
map: ICnMap;
I: Integer;
hql: string;
begin
map := getPodoProperties(data.TableName, data);
hql := Format(DH_ID_GENERATOR, [data.TableName, data.KeyColumnName,
map.get(data.KeyColumnName)]);
with TADOQuery.Create(nil) do
begin
Connection := Self.DataController.Connection;
SQL.Text := hql;
Open;
if RecordCount = 0 then
Append
else
Edit;
for I := 0 to map.size - 1 do
begin
// ShowMessage(map.getTable(i).hashName+':'+string(map.getTable(i).hashValue));
FieldByName(map.getTable(I).hashName).Value := map.getTable(I).hashValue;
end;
try
Post;
result := True;
except
result := false;
end;
Free;
end;
end;
function TDataOperator.saveOrUpdateAllData(dataList: TTableDatalist): Boolean;
var
I: Integer;
begin
result := True;
for I := 0 to dataList.Count - 1 do
begin
if not saveOrUpdate(dataList.Items[I]) then
result := false;
end;
end;
function TDataOperator.updateAllData(dataList: TTableDatalist): Boolean;
var
I: Integer;
begin
result := True;
for I := 0 to dataList.Count - 1 do
begin
if not updateData(dataList.Items[I]) then
result := false;
end;
end;
function TDataOperator.updateData(data: TTableData): Boolean;
var
map: ICnMap;
hql: string;
I: Integer;
begin
map := getPodoProperties(data.TableName, data);
hql := Format(DH_ID_GENERATOR, [data.TableName, data.KeyColumnName,
map.get(data.KeyColumnName)]);
with TADOQuery.Create(nil) do
begin
Connection := Self.DataController.Connection;
SQL.Text := hql;
Open;
if RecordCount = 0 then
begin
result := false;
Free;
Exit;
end;
Edit;
for I := 0 to map.size - 1 do
begin
FieldByName(map.getTable(I).hashName).Value := map.getTable(I).hashValue;
end;
try
Post;
result := True;
except
result := false;
end;
Free;
end;
end;
end.

浙公网安备 33010602011771号