Unable to access field 'Active' as type Integer

Discussion of open issues, suggestions and bugs regarding UniDAC (Universal Data Access Components) for Delphi, C++Builder, Lazarus (and FPC)
Post Reply
Marius2
Posts: 22
Joined: Thu 19 Nov 2009 12:17

Unable to access field 'Active' as type Integer

Post by Marius2 » Mon 13 Apr 2015 12:44

Hello,

We recently purchased UniDac to replace AnyDac/FireDac. As expected there are a couple of differences between the systems, one of them is that UniDac allow's a boolean field in the database to be only approached as Field.AsBoolean=True (while AnyDac did not and only allowed AsInteger=1). This is a problem since we would need to adjust hundreds of references to all boolean field. Is there any solution for this so we can let UniDac interpret booleans just like AnyDac (via integers) and is this solution applyable for ALL available database?

I noticed for example a fieldmapping (Connection.DataTypeMap) but was unable to make any progress in that direction. We have defined booleans in the database via a domain called a TBoolean but we don't know how to use that knowledge in the mappings. Is that possible??

Any other pointers or solutions for this problem?


MsSql: create type TBoolean from bit null
Firebird: CREATE DOMAIN TBOOLEAN AS SMALLINT;
etc..

Btw; For the moment we want AnyDac to be a fallback scenario. We would like UniDac to behave the same as much as is (technical) possible so we can interchange the two systems.

Thanks,
Marius

ViktorV
Devart Team
Posts: 3167
Joined: Wed 30 Jul 2014 07:16

Re: Unable to access field 'Active' as type Integer

Post by ViktorV » Tue 14 Apr 2015 13:14

When calling the TBooleanField.AsInteger property in AnyDAC, the GetAsInteger method of the TField basic class will be called, because the GetAsInteger method of the TBooleanField class is not covered. That in turn will cause the "Cannot access field 'Active' as type Integer" error.
The 'Database Type' combobox is generated not dynamically by retrieved server data, but statically using predefined DBMS data types. Therefore you can't get your predefined data types in this combobox.
You can map data of the DBMS types (Bit of SQL Server, SmallInt of Firebird) to Integer.
To map Bit data (SQL Server) and SmallInt (Firebird) to Integer, set the following Data Type Mapping rules before establishing connection:

Code: Select all

UniConnection.DataTypeMap.AddDBTypeRule(msBit, ftInteger);
UniConnection.DataTypeMap.AddDBTypeRule(ibcSmallInt, ftInteger);
These rules will be applied to data of Bit (SQL Server) and SmallInt (Firebird) types and to your predefined TBoolean data types. To use msBit, ibcSmallInt constants, you should add MSDataTypeMapUni, IBCDataTypeMapUni units to the uses section.
You can also map data with such types using 'Field Name' of the required columns.
Example:

Code: Select all

UniTable.DataTypeMap.AddFieldNameRule(YourFieldName, ftInteger);
More details about Data Type Mapping can be found in the UniDAC documentation: http://www.devart.com/unidac/docs/data_type_mapping.htm

Marius2
Posts: 22
Joined: Thu 19 Nov 2009 12:17

Re: Unable to access field 'Active' as type Integer

Post by Marius2 » Tue 14 Apr 2015 13:26

Thanks Victor,

We will investigate this a bit further..

Marius2
Posts: 22
Joined: Thu 19 Nov 2009 12:17

Re: Unable to access field 'Active' as type Integer

Post by Marius2 » Tue 14 Apr 2015 14:07

Got it working now. Just curious, where does unidac actually recoqnize the bit/smallint and makes it a boolean? (have been searching and debuggign a lot, unable to find :roll:)

FredS
Posts: 264
Joined: Mon 10 Nov 2014 17:52

Re: Unable to access field 'Active' as type Integer

Post by FredS » Wed 15 Apr 2015 00:44

Just make it a Boolean Domain, then map Boolean to Boolean in the "Connection Editor-> Data Type Mapping" and bingo. The UniDac Editor does not pull the Domains from the db nor does it allow entry of items not in the list.

In FB3 Boolean will be part of the built in types so hopefully all you'll need to do is delete the Domain.

Code: Select all

CREATE DOMAIN "BOOLEAN"
 AS Smallint
 DEFAULT 0
 CHECK (value in (0, 1))
;
CREATE DOMAIN DWORD
 AS Bigint
 check ( value between 0 and 4294967295 )
;

Marius2
Posts: 22
Joined: Thu 19 Nov 2009 12:17

Re: Unable to access field 'Active' as type Integer

Post by Marius2 » Wed 15 Apr 2015 06:49

Hi Fred,

In this case the whole point was to make it compatbile with AnyDac/FireDac and to remove the boolean 'detection' avoiding having to adjust ~750k lines of code.

However perhaps we will do this later on (first we have to prove unidac/multidatabase is working as good as AnYDac <Firebird/MsSql/PostGresSql/MySql>).

Thanks,
Marius

FredS
Posts: 264
Joined: Mon 10 Nov 2014 17:52

Re: Unable to access field 'Active' as type Integer

Post by FredS » Wed 15 Apr 2015 17:13

Sorry I never played with AnyDac.

So its easy enough to have a Mapping as Boolean for FB which leaves you with a coding issue where you accessed a Boolean field as integer, correct?

If you are XE3+ then just write a class helper like this, only include the unit if you are using UniDac:

Code: Select all

//MMWIN:CLASSCOPY
unit _MM_Copy_Buffer_;

interface

type
  TBooleanFieldHelper = class helper for TBooleanField
  private
      function GetAsInteger: Integer;
    procedure SetAsInteger(const Value: Integer);
  public
    property AsInteger: Integer read GetAsInteger write SetAsInteger;
  end;


implementation


function TBooleanFieldHelper.GetAsInteger: Integer;
begin
  Result := Ord(Self.Value);
end;

procedure TBooleanFieldHelper.SetAsInteger(const Value: Integer);
begin
  Self.Value := Value<>0;
end;

end.

Marius2
Posts: 22
Joined: Thu 19 Nov 2009 12:17

Re: Unable to access field 'Active' as type Integer

Post by Marius2 » Wed 15 Apr 2015 17:19

Hi Fred,

That is a very clever trick, why didn't we think of that :oops:

Btw; class helpers also work in XE..

Thanks,
Marius

FredS
Posts: 264
Joined: Mon 10 Nov 2014 17:52

Re: Unable to access field 'Active' as type Integer

Post by FredS » Wed 15 Apr 2015 20:12

Marius2 wrote:Hi Fred,
Btw; class helpers also work in XE..
Hmm, I read an article that said in XE3+ you can do this and that with Helpers..
Assumed it was because they came in in XE3 but it turns out their role was expanded in XE3..

Well enough, appears what I do with them isn't supported in XE2..

thanks

Fred

ViktorV
Devart Team
Posts: 3167
Joined: Wed 30 Jul 2014 07:16

Re: Unable to access field 'Active' as type Integer

Post by ViktorV » Thu 16 Apr 2015 11:20

Marius2 wrote:Got it working now. Just curious, where does unidac actually recoqnize the bit/smallint and makes it a boolean? (have been searching and debuggign a lot, unable to find :roll:)
When working with SQL Server, UniDAC creates a TBooleanField for fields of the Bit system type - and this behavior is correct.
When using the InterBase provider, the TCustomUniDataSet.SpecificOptions option of BooleanDomainFields is used, that is True by default. This option will let you enable using TBooleanField objects for fields that have domain of the integer data type, and the domain name contains 'BOOLEAN'.

Marius2
Posts: 22
Joined: Thu 19 Nov 2009 12:17

Re: Unable to access field 'Active' as type Integer

Post by Marius2 » Fri 01 May 2015 11:54

Hello Victor,

I just remember we also have enumerations fitting a ms-sql bit so i doubt that is alway's the case (at least there is 1 exception on that bit-rule in our case). But since we also use domains for ms-sql and that would be really the proper way to recognise booleans. It's ashame MySql does not use domains because its really a powerfull system, but voila...

Just being curious, could you point me in the unidac sources where this boolean recognition is happening? (or where to look for?)

Thanks,
Marius

azyk
Devart Team
Posts: 1119
Joined: Fri 11 Apr 2014 11:47
Location: Alpha Centauri A

Re: Unable to access field 'Active' as type Integer

Post by azyk » Fri 08 May 2015 13:14

See the TMSConverterManager.GetDBType method in the MSDataTypeMap unit.

Post Reply