Bit type data fields - gives error message

Using ADO and SQL server.


I get this error message when I try and post or patch a binary field:

{
  "error":
  {
    "code":"OleException",
    "message":"Conversion failed when converting the varchar value 'T' to data type bit"
  }
}

Its when I send this POST:


  "$id":1,
  "@xdata.type":"XData.Default.contractheader",
  "chid":1,
  "charea":1,
  "chstartdate":"2019-03-01",
  "chchargerollover":true,
  "chnote":"note 12345"
}

The object is coded as follows:

 Tcontractheader = class
  private
    Fchid: integer;
    Fcharea: integer;
    Fchstartdate: tdatetime;
    Fchenddate: tdatetime;
    Fchstartbalance: real;
    Fchpaymentscheme: integer;
    Fchchargehoursperperiod: real;
    Fchperiodchargeamount: real;
    Fchchargerollover: boolean;
    Fchnote: string;

If I take out the boolean field from the object, it works fine.


That's because Aurelius saves boolean properties to a char column in database. I believe your database is an existing one with bit field (not created by Aurelius).

The alternative in this case is create another MSSQL dialect, based on the existing one, that considers boolean fields as bit fields. You can call it MSSQL2, and then when you create connections (IDBConnection interface), just pass the "MSSQL2" dialect explicitly to the adapter. The full source code for an MSSQL2 dialect that uses bit fields is below.
unit Aurelius.SQL.MySql2;

interface
uses
  DB,
  Aurelius.SQL.Interfaces,
  Aurelius.SQL.MySQL;

type
  TMySQL2Generator = class(TMySQLSQLGenerator)
  protected
    function GetEquivalentFieldTypes: TFieldTypeEquivArray; override;
    function ConvertValue(Value: Variant; FromType, ToType: TFieldType): Variant; override;
    function GetSqlDialect: string; override;
  end;

implementation
uses
  Aurelius.SQL.Register;

{ TMySQL2Generator }

function TMySQL2Generator.ConvertValue(Value: Variant; FromType,
  ToType: TFieldType): Variant;
begin
  if (FromType = ftBoolean) and (ToType in [ftShortInt, ftByte]) then
  begin
    if Value = True then
      Result := '1' // 1 = True
    else
      Result := '0'; // 0 = False
  end
  else
  if (FromType in [ftShortInt, ftByte]) and (ToType = ftBoolean) then
  begin
    Result := Value <> 0;
  end
  else
    Result := inherited ConvertValue(Value, FromType, ToType);
end;

function TMySQL2Generator.GetEquivalentFieldTypes: TFieldTypeEquivArray;
begin
  SetLength(Result, 1);

  Result[0].NotSupportedType := ftBoolean;
  Result[0].EquivalentType := ftShortInt;
end;

function TMySQL2Generator.GetSqlDialect: string;
begin
  Result := 'MySQL2';
end;

initialization
  TSQLGeneratorRegister.GetInstance.RegisterGenerator(TMySQL2Generator.Create);

end.
1 Like

Thanks.  That fixed the problem.


But your sample code is actually for 'mysql2'  not 'mssql2'.   I edited it to fix that.

I decided to name the .pas file Aurelius.Sql.mssql2.pas and put it the 

  tmssoftware\businessxe7\aurelius\packages\dxe7\Win32\Release

folder, and add the file to my project.  I'm not sure if that is sensible, but it works for me.

I then added the new unit to the uses part of the connection unit as recommended by an error message at runtime.

unit ConnectionModule;

interface

uses
  Aurelius.Drivers.Interfaces,
  Aurelius.SQL.MSSQL,
  Aurelius.SQL.MSSQL2,


Ok. You don't need the old Aurelius.Sql.MSSQL anymore, and I'd suggest you don't put the new file in the Aurelius folder, since it's part of your application, not Aurelius. Better put in your project folder.


I am using a MySQL database through UNIDAC on generating a XData server.

With the standard settings I also get the error for the Boolean types that are stored as TinyInt in the DB.

In UNIDAC there is the possibility to define a Type mapping in the connection options:
Database Type: Tynyint .... Field Type: integer

This avoids the error.

Data Modeler will generate an integer type for that field.
If you force a Boolean type on the DataModeler conversion you will also be able to get "TRUE/FALSE" values in JSON. So do I.
Example:
The two fields userexist and userregistered are both Tinyints in MySQL

 Maybe this can help to find a way to get a standard solution for the translation of TinyInt in Boolean types when using DataModeler/Aurelius/XData. Maybe as a connection option in the DataModeler?

Hi Francesco,

MySQL shouldn't have the same issue as MSSQL dialect. MySQL already deals boolean as booleans (BIT fields), not as char. A TinyInt is not a boolean anyway, it's an integer value, so DM treats it as integers. Not sure what could be done in this case?
Wagner

Hello Wagner, 

as I tried to explain I put a Mapping in UNIDAC that translate the TinyBit as Integer. Then I force the DataModeler to generate a Boolean field in the class for that integer. This let me retreive the json field as a boolean (true/false). If I avoid all this, the XData cannot handle the situation and I get no Json values at all. It seems like the combination of MySQL TinyInt+UNIDAC+XData is not the optimal one.
Best Regards,
Francesco

Sorry, too much noise into it. There is no "combination" issue as XData/Aurelius is agnostic regarding the database-access component.

What do you want, in essence? You have an integer (TinyInt) field in database and you want to treat it as a boolean field?

Hi Wagner,

I am just happy like that. There is no way to tell MySQL 5.x that a field is of type Boolean. That's why we have TinyInt. Now when I generate the Classes in Datamodeler and I try to use those classes in XData I get an error (later this night, if you are interested, I can try to catch the error and tell you more about that). The only way I have found to come out of the error is to map the TinyInt to an Integer in the Connection properties of UNIDAC. I understand that you can't do anything else as treating a TinyInt for what it is: an Integer. The problem is probably on the UNIDAC side. But I am happy with having found a way to deal with the error without having to change the definition of the database. Over this I have to say that I like XData, Aurelius and all the BIZ staff very much. I still need a little bit of time to get oriented in these all themes, but I am very excited about the new perspectives that open up thanks your products.
Best Regards,
Francesco
"There is no way to tell MySQL 5.x that a field is of type Boolean" - there is the BIT data type. That's what Aurelius and Data Modeler consider to be a Boolean field. TinyInt is an integer value.
Yes, please let me know what error you get, there should be none.
And yes, if the error is on the Unidac side, we can't do much about that indeed - maybe.
Also remember you can always create other properties and map those properties instead of a field. For example:


type
  TMyEntity = class;
  ...
    [Transient] 
    FMyBool: Boolean;
  ...
  [Column('MyTinyIntColumn')]
  property TinyIntValue: Integer read GetTinyIntValue write SetTinyIntValue; 
  property MyBool: Boolean read FMyBool write FMyBool;


function TMyEntity.GetTinyIntValue: Integer;
begin
  if FMyBool then
    Result := 1
  else
    Result := 0;
end;


procedure TMyEntity.SetTinyIntValue(const Value: Integer);
begin
  FMyBool := Value <> 0;
end;



Hello Wagner,

many thanks for your support and explanations.
I tried to reproduce the situation on my windows 10 Laptop (since I'm on the way), but Iwas not successfull in recreating the error. As much as I try to change options in all involved components and database tables I do not find a way to break the XData server. It runs and runs and always produce regular json output. That's beautiful! Haha! I had indeed some problems with the browser configuration on the client side... but this is off topic hier. At the moment everything works fine. 
Many thanks for your patience and great competence (really great how we can create new properties and map them instead of the original field!-this is very handy if we can not change the definition of the DB tables because of other software accessing it),
many thanks for your great software!
Best regards,
Francesco

Glad you have it working, Francesco. Thank you for the nice words.