Решено Zuby и Cody71727172 , может кому пригодиться:
Вообщем кнопочка MyLocation на MapView цепляет данные c LOCATION_SERVICE (Androidapi.JNI.Location)
и если отсутствует GPS датчик в телефоне, тогда:
Прописываем функцию:
function CheckGPSActive: Boolean;
// uses Androidapi.JNIBridge, Androidapi.JNI.Location, Androidapi.JNI.JavaTypes, Androidapi.JNI.GraphicsContentViewText, Androidapi.Helpers
{$IFDEF ANDROID}
var
LocManagerObj: JObject;
LocationManager: JLocationManager;
allProviders: JList;
I: Integer;
begin
Result := false;
LocManagerObj := SharedActivityContext.getSystemService (TJContext.JavaClass.LOCATION_SERVICE); // запрашиваем сервис Location
if Assigned(LocManagerObj) then
begin
LocationManager := TJLocationManager.Wrap((LocManagerObj as ILocalObject).GetObjectID); // получаем LocationManager
if Assigned(LocationManager) then
begin
allProviders := LocationManager.getProviders(true); // запрашиваем список всех провайдеров
if Assigned(allProviders) then
with TStringList.Create do
begin
for I := 0 to allProviders.size - 1 do Add(JStringToString(allProviders.get(I).ToString));
if ((IndexOf('gps') >= 0) or (IndexOf('network') >= 0) or (IndexOf('passive') >= 0)) then
Result := true;
Free;
end;
end;
end;
{$ELSE}
begin
Result := false;
{$ENDIF}
end;
и при запуске LocationSensor например на Form.Create проверяем
procedure TForm_main.FormCreate(Sender: TObject);
begin
{$IFDEF ANDROID}
LocationSensor.Active:=true;
if not LocationSensor.Active then
if not CheckGPSActive then
ShowMessage('Включите GPS для определения Вашего местоположения!')
else
LocationSensor.Active := true;
{$ENDIF}
end;
LocationSensor сам подключит источник данных, поэтому изменять в LSensor1LocationChanged ничего не нужно, например:
procedure TForm_Main.LSensor1LocationChanged(Sender: TObject; const [Ref] OldLocation, NewLocation: TLocationCoord2D);
//uses Maps.Engine
var
MapsEngine: TMapsEngine;
MapsLoc: TMapCoordinate;
MapsData: TMapsEngineGeoData;
begin
MapsLoc := TMapCoordinate.Create(NewLocation.Latitude, NewLocation.Longitude);
MapsEngine.SetOptionsYandex('');
MapsEngine.Geocoding(NewLocation, MapsData);
Edit1.text:= MapsData.FormattedAddress;
end;
Решено Zuby и Cody71727172 , может кому пригодиться:
Вообщем кнопочка MyLocation на MapView цепляет данные c LOCATION_SERVICE (Androidapi.JNI.Location)
и если отсутствует GPS датчик в телефоне, тогда:
Прописываем функцию:
function CheckGPSActive: Boolean;
// uses Androidapi.JNIBridge, Androidapi.JNI.Location, Androidapi.JNI.JavaTypes, Androidapi.JNI.GraphicsContentViewText, Androidapi.Helpers
{$IFDEF ANDROID}
var
LocManagerObj: JObject;
LocationManager: JLocationManager;
allProviders: JList;
I: Integer;
begin
Result := false;
LocManagerObj := SharedActivityContext.getSystemService (TJContext.JavaClass.LOCATION_SERVICE); // запрашиваем сервис Location
if Assigned(LocManagerObj) then
begin
LocationManager := TJLocationManager.Wrap((LocManagerObj as ILocalObject).GetObjectID); // получаем LocationManager
if Assigned(LocationManager) then
begin
allProviders := LocationManager.getProviders(true); // запрашиваем список всех провайдеров
if Assigned(allProviders) then
with TStringList.Create do
begin
for I := 0 to allProviders.size - 1 do Add(JStringToString(allProviders.get(I).ToString));
if ((IndexOf('gps') >= 0) or (IndexOf('network') >= 0) or (IndexOf('passive') >= 0)) then
Result := true;
Free;
end;
end;
end;
{$ELSE}
begin
Result := false;
{$ENDIF}
end;
и при запуске LocationSensor например на Form.Create проверяем
procedure TForm_main.FormCreate(Sender: TObject);
begin
{$IFDEF ANDROID}
LocationSensor.Active:=true;
if not LocationSensor.Active then
if not CheckGPSActive then
ShowMessage('Включите GPS для определения Вашего местоположения!')
else
LocationSensor.Active := true;
{$ENDIF}
end;
LocationSensor сам подключит источник данных, поэтому изменять в LSensor1LocationChanged ничего не нужно, например:
procedure TForm_Main.LSensor1LocationChanged(Sender: TObject; const [Ref] OldLocation, NewLocation: TLocationCoord2D);
//uses Maps.Engine
var
MapsEngine: TMapsEngine;
MapsLoc: TMapCoordinate;
MapsData: TMapsEngineGeoData;
begin
MapsLoc := TMapCoordinate.Create(NewLocation.Latitude, NewLocation.Longitude);
MapsEngine.SetOptionsYandex('');
MapsEngine.Geocoding(NewLocation, MapsData);
Edit1.text:= MapsData.FormattedAddress;
end;
Решено Zuby и Cody71727172 , может кому пригодиться:
Вообщем кнопочка MyLocation на MapView цепляет данные c LOCATION_SERVICE (Androidapi.JNI.Location)
и если отсутствует GPS датчик в телефоне, тогда:
Прописываем функцию:
function CheckGPSActive: Boolean;
// uses Androidapi.JNIBridge, Androidapi.JNI.Location, Androidapi.JNI.JavaTypes, Androidapi.JNI.GraphicsContentViewText, Androidapi.Helpers
{$IFDEF ANDROID}
var
LocManagerObj: JObject;
LocationManager: JLocationManager;
allProviders: JList;
I: Integer;
begin
Result := false;
LocManagerObj := SharedActivityContext.getSystemService (TJContext.JavaClass.LOCATION_SERVICE); // запрашиваем сервис Location
if Assigned(LocManagerObj) then
begin
LocationManager := TJLocationManager.Wrap((LocManagerObj as ILocalObject).GetObjectID); // получаем LocationManager
if Assigned(LocationManager) then
begin
allProviders := LocationManager.getProviders(true); // запрашиваем список всех провайдеров
if Assigned(allProviders) then
with TStringList.Create do
begin
for I := 0 to allProviders.size - 1 do Add(JStringToString(allProviders.get(I).ToString));
if ((IndexOf('gps') >= 0) or (IndexOf('network') >= 0) or (IndexOf('passive') >= 0)) then
Result := true;
Free;
end;
end;
end;
{$ELSE}
begin
Result := false;
{$ENDIF}
end;
и при запуске LocationSensor например на Form.Create проверяем
procedure TForm_main.FormCreate(Sender: TObject);
begin
{$IFDEF ANDROID}
LocationSensor.Active:=true;
if not LocationSensor.Active then
if not CheckGPSActive then
ShowMessage('Включите GPS для определения Вашего местоположения!')
else
LocationSensor.Active := true;
{$ENDIF}
end;
LocationSensor сам подключит источник данных, поэтому изменять в LSensor1LocationChanged ничего не нужно, например:
procedure TForm_Main.LSensor1LocationChanged(Sender: TObject; const [Ref] OldLocation, NewLocation: TLocationCoord2D);
//uses Maps.Engine
var
MapsEngine: TMapsEngine;
MapsLoc: TMapCoordinate;
MapsData: TMapsEngineGeoData;
begin
MapsLoc := TMapCoordinate.Create(NewLocation.Latitude, NewLocation.Longitude);
MapsEngine.SetOptionsYandex('');
MapsEngine.Geocoding(NewLocation, MapsData);
Edit1.text:= MapsData.FormattedAddress;
end;
Решено Zuby и Cody71727172 , может кому пригодиться:
Вообщем кнопочка MyLocation на MapView цепляет данные c LOCATION_SERVICE (Androidapi.JNI.Location)
и если отсутствует GPS датчик в телефоне, тогда:
Прописываем функцию:
function CheckGPSActive: Boolean;
// uses Androidapi.JNIBridge, Androidapi.JNI.Location, Androidapi.JNI.JavaTypes, Androidapi.JNI.GraphicsContentViewText, Androidapi.Helpers
{$IFDEF ANDROID}
var
LocManagerObj: JObject;
LocationManager: JLocationManager;
allProviders: JList;
I: Integer;
begin
Result := false;
LocManagerObj := SharedActivityContext.getSystemService (TJContext.JavaClass.LOCATION_SERVICE); // запрашиваем сервис Location
if Assigned(LocManagerObj) then
begin
LocationManager := TJLocationManager.Wrap((LocManagerObj as ILocalObject).GetObjectID); // получаем LocationManager
if Assigned(LocationManager) then
begin
allProviders := LocationManager.getProviders(true); // запрашиваем список всех провайдеров
if Assigned(allProviders) then
with TStringList.Create do
begin
for I := 0 to allProviders.size - 1 do Add(JStringToString(allProviders.get(I).ToString));
if ((IndexOf('gps') >= 0) or (IndexOf('network') >= 0) or (IndexOf('passive') >= 0)) then
Result := true;
Free;
end;
end;
end;
{$ELSE}
begin
Result := false;
{$ENDIF}
end;
и при запуске LocationSensor например на Form.Create проверяем
procedure TForm_main.FormCreate(Sender: TObject);
begin
{$IFDEF ANDROID}
LocationSensor.Active:=true;
if not LocationSensor.Active then
if not CheckGPSActive then
ShowMessage('Включите GPS для определения Вашего местоположения!')
else
LocationSensor.Active := true;
{$ENDIF}
end;
LocationSensor сам подключит источник данных, поэтому изменять в LSensor1LocationChanged ничего не нужно, например:
procedure TForm_Main.LSensor1LocationChanged(Sender: TObject; const [Ref] OldLocation, NewLocation: TLocationCoord2D);
//uses Maps.Engine
var
MapsEngine: TMapsEngine;
MapsLoc: TMapCoordinate;
MapsData: TMapsEngineGeoData;
begin
MapsLoc := TMapCoordinate.Create(NewLocation.Latitude, NewLocation.Longitude);
MapsEngine.SetOptionsYandex('');
MapsEngine.Geocoding(NewLocation, MapsData);
Edit1.text:= MapsData.FormattedAddress;
end;
Всем здоровья, вообщем ситуация следующая имеется телефон без GPS датчика, но нужны координаты.
Подскажите как можно их вытащить
Например при отображении MapView на ней кнопочка MyLocation которая даже без датчика достаточно точно показывает местоположения.
Вообщем как вытащить эти координаты UserLocation не отображая карту (может в системных данных где то)?
Или как программно нажать MyLocation, чтобы после центрирования карты получить координаты MapView.Position?
Реверс Геокодинг по вайфай или мобильным данным (ip-адрес) совсем не то.
Для подключения к базе на удаленном хостинге, необходимо:
1. Выделенный IP адрес, (хостинг на выделенном сервере или VDS)
2. На сервере настроить в брэндмауре пакеты MySQL на порт 3306 (по умолчанию)
3. Возможно на маршрутизаторе хостинга закрыты порты, обычно нужно написать чтобы открыли порт.
4. Настроить сам MySQL, добавить учетную запись на соединение из вне или дать доступ root (не желательно).
5. Зайдите на сервер лучше по RDP (удаленный рабочий стол), и можете через программу dbForge (бесплатная) добавить учетную запись, указав подключение хоть от куда (то есть %)
6. Далее попробуйте подключиться для начала со своего компьютера через dbForge
7. FireDac не использую, там херь какую то надо настраивать с драйверам)), но ZuBy позже скинет исходник коннекта к MySQL через FireDac.
8. Использую платный MyDac от Devart, если вам лень и вы НЕ СМОЖЕТЕ с FireDac работать (как я), тогда могу скинуть свой MyDac. писать в ЛС.
Andy, вы просто не умеете их готовить
В других IDE/языках тоже проблем и глюков более чем есть.
А по факту - я надеюсь, что FMX не остановят в развитии. Имхо, Embarcadero сейчас в направлении кросс-платформенности впереди планеты всей.
Повторюсь - это было имхо и не повод для холиваров.
Aptem, а не проще было бы сделать сервак(web например) и тогда ваши провайдеры просто не нужны.
разработать протокол обмена данными по средствам json\xml и тогда не нужно было бы заботить о клиентских приложениях и какая бд используется
вся работа перекладывается на сервак, хоть каждый месяц меняйте БД, просто переписать сервак и все клиенты снова получают и отправляют актуальную информацию
для Delphi 10 Seatlle вышел
30398_paserver_hotfix_for_delphi_c_builder_and_rad_studio_10_seattle
This PAServer Hotfix provides fixes for:
- building OS X 10.11 (El Capitan) applications with Delphi, C++Builder and RAD Studio 10 Seattle
- building iOS applications that run on iOS 7, iOS 8 and iOS 9 using the iOS 9 SDK with Delphi, C++Builder and RAD Studio 10 Seattle
Все просто, если вы выставите флаг AllowTracking в True, то диалоговое окно не будет показано при запуске. Соответственно, после первого запуска, вы должны куда-нибудь сохранить информацию, что пользователь дал добро на отслеживание. Для этого вам предлагают использовать уже готовый механизм для сохранения данных при закрытии приложении. Так же вы можете в ручную реализовать сохранение настроек через XMl, Ini файлы и тд. [Android] Что использовать для сохранения настроек приложения? FireMonkey Save State
В своих разработках мы придерживаемся принципа разделения приложения на слои:
1. Слой доступа к данным - DAL
2. Слой бизнес-логики - BL
3. Слой представления - UI
В связи с этим большую часть модулей приложений мы разрабатываем вручную, не прибегая к использованию визуальных компонентов. Все визуальные компоненты (кнопки, гриды, мемо и т. п.) только в слое UI. Также мы поступили и со слоем DAL, разработав собственный провайдер для доступа к базе данных Oracle. Активно используем его уже лет 5 и пока он покрывает все наши нужды.
Представляю его вашему вниманию и прошу объективной критики по любому поводу.
Интерфейс провайдера:
unit OracleProviderInterface;
interface
uses
Ora, DB, Variants, SysUtils, Classes, Contnrs,
Spring.Collections
;
/// <summary>
/// Parameters data type enumeration
/// </summary>
type
TParamDataType = ( pdtDefault = 1, pdtBlob = 2, pdtTable = 3, pdtClob = 4 );
/// <summary>
/// Class for CDB database parameter
/// </summary>
type
TCDBOraParam = Class ( TOraParam )
public
{$REGION 'Fields'}
/// <summary>
/// Gets or sets parameter data type
/// </summary>
ParamDataType : TParamDataType;
{$ENDREGION}
{$REGION 'Constructors'}
/// <summary>
/// Creates TCDBOraParam instance
/// </summary>
constructor Create ();
{$ENDREGION}
end;
/// <summary>
/// Interface for database provider
/// </summary>
type
IDatabaseProvider = interface ( IInterface )
['{BF277F9C-D046-4015-8E17-6B4C67CC021B}']
{$REGION 'Methods'}
/// <summary>
/// Executes SQL query passed with parameters
/// </summary>
/// <param name="query">SQL query text</param>
/// <param name="parameters">Binded query parameters</param>
/// <returns>Query execution results</returns>
function ExecuteQuery ( query : String; const parameters : IList<TCDBOraParam> = nil ) : TDataSet;
/// <summary>
/// Executes non-selective (insert, update, delete) SQL passed with parameters
/// </summary>
/// <param name="query">SQL query text</param>
/// <param name="parameters">Binded query parameters</param>
/// <returns>Number of rows affected</returns>
function ExecuteNonQuery ( query : String; const parameters : IList<TCDBOraParam> = nil ) : Integer;
/// <summary>
/// Executes stored procedure with particular parameters
/// </summary>
/// <param name="procedureName">Stored procedure name</param>
/// <param name="parameters">Binded query parameters</param>
/// <returns>Execution results</returns>
function ExecuteProcedure ( procedureName : String; const parameters : IList<TCDBOraParam> = nil ) : TOraParams;
/// <summary>
/// Begins session transaction
/// </summary>
procedure BeginTransaction ();
/// <summary>
/// Commits current session transaction
/// </summary>
procedure CommitTransaction ();
/// <summary>
/// Rollbacks current session transaction
/// </summary>
procedure RollbackTransaction ();
/// <summary>
/// Creates parameter
/// </summary>
/// <param name="name">Parameter name</param>
/// <param name="value">Parameter value</param>
/// <param name="paramType">Parameter type (e.g. input or output)</param>
/// <param name="paramDataType">Parameter data type (e.g. default or BLOB)</param>
/// <returns>Binded parameter</returns>
function CreateParameter ( name : String; value : Variant; paramType : TParamType = ptInput; paramDataType : TParamDataType = pdtDefault ) : TCDBOraParam; overload;
/// <summary>
/// Connects to the server
/// </summary>
procedure OpenSession ();
/// <summary>
/// Disconnects from the server
/// </summary>
procedure CloseSession ();
/// <summary>
/// Gets session
/// </summary>
/// <returns>Connection session</returns>
function GetSession () : TOraSession;
{$ENDREGION}
{$REGION 'Properties'}
/// <summary>
/// Connection session
/// </summary>
property Session : TOraSession read GetSession;
{$ENDREGION}
end;
implementation
{ TCDBOraParam }
/// <summary>
/// Creates TCDBOraParam instance
/// </summary>
constructor TCDBOraParam.Create ();
begin
inherited Create ( nil );
ParamDataType := pdtDefault;
end;
end.
Реализация:
unit OracleProvider;
interface
uses
Ora, DB, Variants, SysUtils, Classes, Contnrs, MemData, DBAccess,
Spring.Container,
Spring.Collections,
//BL
OracleProviderInterface
;
/// <summary>
/// Data provider to Oracle database
/// </summary>
type
TOracleProvider = class ( TInterfacedObject, IDatabaseProvider )
private
{$REGION 'Fields'}
/// <summary>
/// Database session
/// </summary>
_session : TOraSession;
/// <summary>
/// Query
/// </summary>
_query : TOraQuery;
/// <summary>
/// SQL-expression
/// </summary>
_sql : TOraSQL;
/// <summary>
/// Stored procedure
/// </summary>
_storedProcedure : TOraStoredProc;
/// <summary>
/// Flag to understand who owns session
/// </summary>
_isOwnSession : Boolean;
/// <summary>
/// Connection string
/// </summary>
_connectionString : String;
{$ENDREGION}
{$REGION 'Methods'}
/// <summary>
/// Gets parameter's field type by Variant value
/// </summary>
/// <param name="value">value</param>
/// <returns>Field type for TOraParam</returns>
function GetFieldType ( value : Variant ) : TFieldType;
/// <summary>
/// Initializes class inner objects
/// </summary>
/// <param name="isOwnSession">Flag to understand who owns session</param>
procedure Initialize ( isOwnSession : Boolean );
/// <summary>
/// Gets session
/// </summary>
/// <returns>Connection session</returns>
function GetSession () : TOraSession;
{$ENDREGION}
public
{$REGION 'Methods'}
/// <summary>
/// Executes SQL query passed with parameters
/// </summary>
/// <param name="query">SQL query text</param>
/// <param name="parameters">Binded query parameters</param>
/// <returns>Query execution results</returns>
function ExecuteQuery ( query : String; const parameters : IList<TCDBOraParam> = nil ) : TDataSet;
/// <summary>
/// Executes non-selective (insert, update, delete) SQL passed with parameters
/// </summary>
/// <param name="query">SQL query text</param>
/// <param name="parameters">Binded query parameters</param>
/// <returns>Number of rows affected</returns>
function ExecuteNonQuery ( query : String; const parameters : IList<TCDBOraParam> = nil ) : Integer;
/// <summary>
/// Executes stored procedure with particular parameters
/// </summary>
/// <param name="procedureName">Stored procedure name</param>
/// <param name="parameters">Binded query parameters</param>
/// <returns>Execution results</returns>
function ExecuteProcedure ( procedureName : String; const parameters : IList<TCDBOraParam> = nil ) : TOraParams;
/// <summary>
/// Begins session transaction
/// </summary>
procedure BeginTransaction ();
/// <summary>
/// Commits current session transaction
/// </summary>
procedure CommitTransaction ();
/// <summary>
/// Rollbacks current session transaction
/// </summary>
procedure RollbackTransaction ();
/// <summary>
/// Creates parameter
/// </summary>
/// <param name="name">Parameter name</param>
/// <param name="value">Parameter value</param>
/// <param name="paramType">Parameter type (e.g. input or output)</param>
/// <param name="paramDataType">Parameter data type (e.g. default or BLOB)</param>
/// <returns>Binded parameter</returns>
function CreateParameter ( name : String; value : Variant; paramType : TParamType = ptInput; paramDataType : TParamDataType = pdtDefault ) : TCDBOraParam; overload;
/// <summary>
/// Connects to the server
/// </summary>
procedure OpenSession ();
/// <summary>
/// Disconnects from the server
/// </summary>
procedure CloseSession ();
{$ENDREGION}
{$REGION 'Constructors'}
/// <summary>
/// Creates TOracleProvider instance with particular connection string
/// </summary>
/// <param name="connectionString">Connection string</param>
constructor Create ( const connectionString : String ); overload;
/// <summary>
/// Creates TOracleProvider instance with particular session
/// </summary>
/// <param name="oracleSession">Connection session</param>
constructor Create ( const oracleSession : TOraSession ); overload;
{$ENDREGION}
{$REGION 'Destructors'}
/// <summary>
/// Safely destroys TOracleProvider instance
/// </summary>
destructor Destroy (); override;
{$ENDREGION}
{$REGION 'Properties'}
/// <summary>
/// Connection session
/// </summary>
property Session : TOraSession read GetSession;
{$ENDREGION}
end;
implementation
{TOracleProvider}
/// <summary>
/// Creates TOracleProvider instance with particular connection string
/// </summary>
/// <param name="connectionString">Connection string</param>
constructor TOracleProvider.Create ( const connectionString : String );
begin
_connectionString := connectionString;
Initialize ( true );
end;
/// <summary>
/// Creates TOracleProvider instance with particular session
/// </summary>
/// <param name="oracleSession">Connection session</param>
constructor TOracleProvider.Create ( const oracleSession : TOraSession );
begin
_session := oracleSession;
Initialize ( false );
end;
/// <summary>
/// Initializes class inner objects
/// </summary>
/// <param name="isOwnSession">Flag to understand who owns session</param>
procedure TOracleProvider.Initialize ( isOwnSession : Boolean );
begin
if isOwnSession then begin
_session := TOraSession.Create ( nil );
_session.ConnectString := _connectionString;
_session.Connected := false;
_session.LoginPrompt := false;
_session.Options.Direct := true;
_session.AutoCommit := false;
_session.Options.NeverConnect := true;
_session.Pooling := true;
end;
_query := TOraQuery.Create ( nil );
_query.Session := _session;
_query.AutoCommit := false;
_query.FetchAll := true;
_sql := TOraSQL.Create ( nil );
_sql.Session := _session;
_sql.AutoCommit := false;
_storedProcedure := TOraStoredProc.Create ( nil );
_storedProcedure.Session := _session;
_storedProcedure.AutoCommit := false;
_storedProcedure.FetchAll := true;
_isOwnSession := isOwnSession;
end;
/// <summary>
/// Safely destroys TOracleProvider instance
/// </summary>
destructor TOracleProvider.Destroy ();
begin
if _query.Active then begin
_query.Close ();
end;
_query.Free ();
if _storedProcedure.Active then begin
_storedProcedure.Close ();
end;
_storedProcedure.Free ();
if _isOwnSession then begin
if _session.Connected then begin
_session.Close ();
end;
_session.Free ();
end;
inherited;
end;
/// <summary>
/// Connects to the server
/// </summary>
procedure TOracleProvider.OpenSession ();
begin
if _session <> nil then begin
try
_session.Open ();
except
on e : Exception do begin
raise Exception.Create ( e.Message );
end;
end;
end;
end;
/// <summary>
/// Disconnects from the server
/// </summary>
procedure TOracleProvider.CloseSession ();
begin
if _isOwnSession then begin
if ( _session <> nil ) AND ( _session.Connected ) then begin
try
_session.Close ();
except
on e : Exception do begin
raise Exception.Create ( e.Message );
end;
end;
end;
end;
end;
/// <summary>
/// Begins session transaction
/// </summary>
procedure TOracleProvider.BeginTransaction ();
begin
try
_session.StartTransaction ();
except
on e : Exception do begin
raise Exception.Create ( e.Message );
end;
end;
end;
/// <summary>
/// Commits current session transaction
/// </summary>
procedure TOracleProvider.CommitTransaction ();
begin
if _session.InTransaction then begin
try
_session.Commit ();
except
on e : Exception do begin
raise Exception.Create ( e.Message );
end;
end;
end;
end;
/// <summary>
/// Rollbacks current session transaction
/// </summary>
procedure TOracleProvider.RollbackTransaction ();
begin
if _session.InTransaction then begin
try
_session.Rollback ();
except
on e : Exception do begin
raise Exception.Create ( e.Message );
end;
end;
end;
end;
/// <summary>
/// Executes SQL query passed with parameters
/// </summary>
/// <param name="query">SQL query text</param>
/// <param name="parameters">Binded query parameters</param>
/// <returns>Query execution results</returns>
function TOracleProvider.ExecuteQuery ( query : String; const parameters : IList<TCDBOraParam> = nil ) : TDataSet;
var
i : Integer;
param : TOraParam;
dataSet : TDataSet;
begin
dataSet := TDataSet.Create ( nil );
_query.Close ();
_query.SQL.Text := query;
if Assigned ( parameters ) then begin
_query.Params.Clear ();
for i := 0 to parameters.Count - 1 do begin
param := TOraParam.Create ( nil );
param.Name := TOraParam ( parameters[i] ).Name;
param.Value := TOraParam ( parameters[i] ).Value;
param.ParamType := TOraParam ( parameters[i] ).ParamType;
_query.Params.AddParam ( param );
end;
end;
try
if _session.Connected then begin
_query.Execute ();
dataSet := _query.Fields.DataSet;
dataSet.Active := true;
end;
except
on e : Exception do begin
raise Exception.Create ( e.Message );
end;
end;
Result := dataSet;
end;
/// <summary>
/// Executes stored procedure with particular parameters
/// </summary>
/// <param name="procedureName">Stored procedure name</param>
/// <param name="parameters">Binded query parameters</param>
/// <returns>Execution results</returns>
function TOracleProvider.ExecuteProcedure ( procedureName : String; const parameters : IList<TCDBOraParam> = nil ) : TOraParams;
var
i : Integer;
j : Integer;
begin
_storedProcedure.Close ();
_storedProcedure.StoredProcName := procedureName;
_storedProcedure.Prepare ();
if Assigned ( parameters ) then begin
for i := 0 to parameters.Count - 1 do begin
for j := 0 to _storedProcedure.Params.Count - 1 do begin
if _storedProcedure.Params[j].Name = TOraParam ( parameters[i] ).Name then begin
_storedProcedure.Params[j] := TOraParam ( parameters[i] );
if TCDBOraParam ( parameters[i] ).ParamDataType = pdtBlob then begin
if ( ( TOraParam ( parameters[i] ).Value <> Null ) AND ( TOraParam ( parameters[i] ).Value <> '') ) then begin
_storedProcedure.ParamByName ( TOraParam ( parameters[i] ).Name ).DataType := ftOraBlob;
_storedProcedure.ParamByName ( TOraParam ( parameters[i] ).Name ).ParamType := TOraParam ( parameters[i] ).ParamType;
_storedProcedure.ParamByName ( TOraParam ( parameters[i] ).Name ).AsOraBlob.LoadFromFile ( TOraParam ( parameters[i] ).Value );
end
else begin
_storedProcedure.ParamByName ( TOraParam ( parameters[i] ).Name ).DataType := ftOraBlob;
_storedProcedure.ParamByName ( TOraParam ( parameters[i] ).Name ).ParamType := TOraParam ( parameters[i] ).ParamType;
_storedProcedure.ParamByName ( TOraParam ( parameters[i] ).Name ).AsOraBlob.FreeBlob ();
end;
end;
if TCDBOraParam ( parameters[i] ).ParamDataType = pdtClob then begin
if ( ( TOraParam ( parameters[i] ).Value <> Null ) AND ( TOraParam ( parameters[i] ).Value <> '') ) then begin
_storedProcedure.ParamByName ( TOraParam ( parameters[i] ).Name ).DataType := ftOraClob;
_storedProcedure.ParamByName ( TOraParam ( parameters[i] ).Name ).ParamType := TOraParam ( parameters[i] ).ParamType;
_storedProcedure.ParamByName ( TOraParam ( parameters[i] ).Name ).Value := TOraParam ( parameters[i] ).Value;
end;
end;
end;
end;
end;
end;
if _session.Connected then begin
try
_storedProcedure.Execute ();
Result := _storedProcedure.Params;
except
on e : Exception do begin
raise Exception.Create ( e.Message );
end;
end;
end
else begin
Result := TOraParams.Create ( nil );
end;
end;
/// <summary>
/// Executes non-selective (insert, update, delete) SQL passed with parameters
/// </summary>
/// <param name="query">SQL query text</param>
/// <param name="parameters">Binded query parameters</param>
/// <returns>Number of rows affected</returns>
function TOracleProvider.ExecuteNonQuery ( query : String; const parameters : IList<TCDBOraParam> = nil ) : Integer;
var
i : Integer;
begin
_query.Close ();
_query.SQL.Clear ();
_query.SQL.Text := query;
if Assigned ( parameters ) then begin
_query.Params.Clear ();
for i := 0 to parameters.Count - 1 do begin
_query.Params.AddParam ( TOraParam ( parameters[i] ) );
end;
end;
if _session.Connected then begin
_query.ExecSQL ();
Result := _query.RowsAffected;
end
else begin
Result := 0;
end;
end;
/// <summary>
/// Creates parameter
/// </summary>
/// <param name="name">Parameter name</param>
/// <param name="value">Parameter value</param>
/// <param name="paramType">Parameter type (e.g. input or output)</param>
/// <param name="paramDataType">Parameter data type (e.g. default or BLOB)</param>
/// <returns>Binded parameter</returns>
function TOracleProvider.CreateParameter ( name : String; value : Variant; paramType : TParamType = ptInput; paramDataType : TParamDataType = pdtDefault ) : TCDBOraParam;
var
parameter : TCDBOraParam;
begin
parameter := TCDBOraParam.Create ();
parameter.Name := UpperCase ( name );
parameter.ParamType := paramType;
parameter.DataType := GetFieldType ( value );
case paramDataType of
pdtDefault:
begin
parameter.Value := value;
end;
pdtBlob:
begin
parameter.Value := value;
end;
pdtClob:
begin
parameter.Value := value;
end;
pdtTable:
begin
parameter.Table := true;
parameter.DataType := ftFloat;
parameter.Value := value;
end;
end;
parameter.ParamDataType := paramDataType;
Result := parameter;
end;
/// <summary>
/// Gets parameter's field type by Variant value
/// </summary>
/// <param name="value">value</param>
/// <returns>Field type for TOraParam</returns>
function TOracleProvider.GetFieldType ( value : Variant ) : TFieldType;
var
fieldType : TFieldType;
begin
case VarType ( value ) AND VarTypeMask of
varString : fieldType := TFieldType.ftWideString;
varUString : fieldType := TFieldType.ftWideString;
varInteger : fieldType := TFieldType.ftInteger;
varByte : fieldType := TFieldType.ftInteger;
varDate : fieldType := TFieldType.ftDate;
else
fieldType := TFieldType.ftUnknown;
end;
Result := fieldType;
end;
/// <summary>
/// Gets session
/// </summary>
/// <returns>Connection session</returns>
function TOracleProvider.GetSession () : TOraSession;
begin
Result := _session;
end;
initialization
GlobalContainer.RegisterType<TOracleProvider>.Implements<IDatabaseProvider> ( 'Oracle' );
end.
Использование:
1. Объявляем:
var _provider : IDatabaseProvider;
2. Инициализируем:
var _connectionString := login + '/' + password + '@' + HostName + ':' + Port + ':' + SID;
_provider := GlobalContainer.Resolve<IDatabaseProvider> ( 'Oracle', [connectionString] );
_provider.OpenSession ();
3. Собственно использование:
3.1 Получаем выборку (SELECT):
function TVSPHelper.GetVSPListByWellId ( wellId : Integer ) : IList<IVSP>;
var
list : IList<IVSP>;
item : IVSP;
query : String;
dataSet : TDataSet;
i : Integer;
j : Integer;
parameters: IList<TCDBOraParam>;
report : IReport;
begin
query := 'SELECT ' +
'id, ' +
'comments, ' +
'wellbore_id, ' +
'wellbore_name, ' +
'wellbore_comments, ' +
'wellbore_depth, ' +
'begin_date, ' +
'end_date, ' +
'expedition_id, ' +
'expedition_name, ' +
'organization_id, ' +
'organization_name, ' +
'subject_id, ' +
'subject_name, ' +
'well_id, ' +
'well_name, ' +
'well_comments, ' +
'well_x, ' +
'well_y, ' +
'well_altitude, ' +
'well_rotary_table_elevation ' +
' FROM ' +
'seis.v_vsp ' +
' WHERE ' +
'well_id = :ID ';
parameters := TCollections.CreateList<TCDBOraParam> ( true );
parameters.Add ( _provider.CreateParameter ( 'ID', wellId ) );
dataSet := _provider.ExecuteQuery ( query, parameters );
list := TCollections.CreateList<IVSP>;
dataSet.First ();
for i := 0 to dataSet.RecordCount - 1 do begin
item := GlobalContainer.Resolve<IVSP>;
item.Id := dataSet.FieldByName ( 'id' ).AsInteger;
item.Comments := dataSet.FieldByName ( 'comments' ).AsString;
item.BeginDate := dataSet.FieldByName ( 'begin_date' ).AsDateTime;
item.EndDate := dataSet.FieldByName ( 'end_date' ).AsDateTime;
item.Wellbore.Id := dataSet.FieldByName ( 'wellbore_id' ).AsInteger;
item.Wellbore.Name := dataSet.FieldByName ( 'wellbore_name' ).AsString;
item.Wellbore.Comments := dataSet.FieldByName ( 'wellbore_comments' ).AsString;
item.Wellbore.Depth := dataSet.FieldByName ( 'wellbore_depth' ).AsFloat;
item.Expedition.Id := dataSet.FieldByName ( 'expedition_id' ).AsInteger;
item.Expedition.Name := dataSet.FieldByName ( 'expedition_name' ).AsString;
item.Organization.Id := dataSet.FieldByName ( 'organization_id' ).AsInteger;
item.Organization.Name := dataSet.FieldByName ( 'organization_name' ).AsString;
item.Wellbore.Well.Subject.Id := dataSet.FieldByName ( 'subject_id' ).AsInteger;
item.Wellbore.Well.Subject.Name := dataSet.FieldByName ( 'subject_name' ).AsString;
item.Wellbore.Well.Id := dataSet.FieldByName ( 'well_id' ).AsInteger;
item.Wellbore.Well.Name := dataSet.FieldByName ( 'well_name' ).AsString;
item.Wellbore.Well.Comments := dataSet.FieldByName ( 'well_comments' ).AsString;
item.Wellbore.Well.X := dataSet.FieldByName ( 'well_x' ).AsFloat;
item.Wellbore.Well.Y := dataSet.FieldByName ( 'well_y' ).AsFloat;
item.Wellbore.Well.Altitude := dataSet.FieldByName ( 'well_altitude' ).AsFloat;
item.Wellbore.Well.RotaryTableElevation := dataSet.FieldByName ( 'well_rotary_table_elevation' ).AsFloat;
list.Add ( item );
dataSet.Next ();
end;
Result := list;
end;
3.2 Вызов хранимой процедуры:
function TVSPHelper.GetShotpointMap ( shotpoint : IVSPShotpoint ) : String;
var
procedureName : String;
parameters: IList<TCDBOraParam>;
returnParameters : TOraParams;
imageURL : String;
errorCode : Integer;
errorMessage : String;
begin
procedureName := 'seis.geometric_functions.p_get_shotpoint_map';
parameters := TCollections.CreateList<TCDBOraParam> ( true );
parameters.Add ( _provider.CreateParameter ( 'operation', 0 ) );
parameters.Add ( _provider.CreateParameter ( 'shotpoint_id_in', shotpoint.Id ) );
parameters.Add ( _provider.CreateParameter ( 'image_url', '', ptOutput ) );
parameters.Add ( _provider.CreateParameter ( 'error_code', 0, ptOutput ) );
parameters.Add ( _provider.CreateParameter ( 'error_message', '', ptOutput ) );
try
_provider.BeginTransaction ();
returnParameters := _provider.ExecuteProcedure ( procedureName, parameters );
imageURL := returnParameters.ParamByName ( 'image_url' ).AsString;
errorCode := returnParameters.ParamByName ( 'error_code' ).AsInteger;
errorMessage := returnParameters.ParamByName ( 'error_message' ).AsString;
if errorCode = 0 then begin
_provider.CommitTransaction ();
end
else begin
_provider.RollbackTransaction ();
end;
except
_provider.RollbackTransaction ();
raise;
end;
imageURL := AnsiReplaceStr ( imageURL, 'https', 'http' );
Result := imageURL;
end;
3.3 Выполнение операций CRUD:
procedure TAdministrationUserHelper.SetUserStatus ( userId : Integer; status : Integer );
var
query : String;
begin
query := 'UPDATE seis.users SET status_id = ' + IntToStr ( status );
try
Provider.BeginTransaction ();
Provider.ExecuteNonQuery ( query );
Provider.CommitTransaction ();
except
Provider.RollbackTransaction ();
raise;
end;
end;
Стоит заметить, что данный провайдер прекрасно подходит как для десктоп-приложений, так и для мобильных приложений. Конечно с небольшими изменениями, но принцип и структура не меняются. Кому будет интересно, могу выложить код провайдера для работы с БД SQLite, который я использовал для приложений под iOS.
Не должен клиент напрямую коннектиться к базе. Должна быть прослойка. Пофигу: тонкая или толстая. Если бизнес логика предполагает миграцию на другую бд - толстая, есои нет - бизнес в пакетах\процедурах. Нельзя с клиента напрямую к бд идти. Должен быть rest-сервис. Пофигу - tcp\http, на дельфях он или на джаве, на питоне, на асп.нете... Клиент должен идти через прослойку. Имхо
function JSONParse(const aJSONData: string; const aMemo: TMemo): boolean;
var
aJSValue: TJSONValue;
aJSObject: TJSONObject;
aJSArray: TJSONArray;
I, J: integer;
begin
Result := false;
aJSValue := TJSONObject.ParseJSONValue(aJSONData) as TJSONValue;
if Assigned(aJSValue) then
begin
aJSObject := aJSValue as TJSONObject;
if Assigned(aJSObject) then
begin
for I := 0 to aJSObject.Count - 1 do
begin
aMemo.Lines.Add(aJSObject.Pairs[I].JsonString.Value + '=' + aJSObject.Pairs[I].JsonValue.Value);
if aJSObject.GetValue(aJSObject.Pairs[I].JsonString.Value) is TJSONArray then
begin
aJSArray := aJSObject.GetValue(aJSObject.Pairs[I].JsonString.Value) as TJSONArray;
if Assigned(aJSArray) then
begin
for J := 0 to aJSArray.Count - 1 do
aMemo.Lines.Add(aJSArray.Items[J].Value);
end;
end;
end;
end;
end;
Result := true;
end;
JSONParse('{"desc":"Описания...","otdel":["1","12","300"],"manufacturer":"ООО \"Привет\""}', Memo1)
Заинтриговала паста о том что халявы не будет... Разработчик с СНГ уже несколько версий подряд ломает делфи. И даже если ему станет лень - в любом случае китайцы ломанут...
Лови ipad estay
https://www.dropbox.com/s/527supdlc565umw/20150923_183759.jpg?dl=0
Только в модуле uDevice на 137 кажись строке для виза отсутствовал энд. Рекомендую поправить иначе не компилится под ИОС.