Accessing record field by reference - record

I have to use records in Lazarus (due to TVirtualStringTree).
If I have a simple record:
type
myrec = record
name: string;
end;
Is there a way how to access the field by reference? i.e. to make a function:
getField('name', searchRecord);
or is there a way how to iterate over fieldnames?

i guest you can use JSON theres fpjson unit on lazarus
http://freepascal.org/docs-html/fcl/fpjson/index.html

Related

Change profile custom field type (Sitefinity 6.3)

I have an old installation of Sitefinity (version 6.3)
On the profile, I have a custom field that is numeric. I now have the needs to change this to hold a string instead.
What I found was that there is no easy way to change datatype (https://www.progress.com/documentation/sitefinity-cms/edit-an-existing-custom-field), but is It possible by code/config?
I'm guessing that one option is to delete the field, and then recreate it is a possibility, but since I have much data it would be a lot of work to restore data in the field. Is this the only way?
Edit: I've deleted the column and recreated it as a string/varchar.
I'm now facing a problem with some type of converter
type converter initialization failed. The converter with name 'DecimalConverter' does not convert from CLR type 'System. String' to SQL type 'DECIMAL'.
Parameter name: converterName
Actual value was OpenAccessRuntime.Data.DecimalConverter, Telerik.OpenAccess.Runtime, Version=2013.3.1211.3, Culture=neutral, PublicKeyToken=7ce17eeaf1d59342.
This line in stack trace is of importance
[MetadataException: The metadata for field 'CustomerNo_sv' of class 'Telerik.Sitefinity.Security.Model.SitefinityProfile' cannot be initialized: Type converter initialization failed. The converter with name 'DecimalConverter' does not convert from CLR type 'System. String' to SQL type 'DECIMAL'.
Parameter name: converterName
Actual value was OpenAccessRuntime.Data.DecimalConverter, Telerik.OpenAccess.Runtime, Version=2013.3.1211.3, Culture=neutral, PublicKeyToken=7ce17eeaf1d59342.]
Somehow the language specified values isn't converted as I can see. Now the whole site is down and I can't reach backend. So I guess I have to solve this out in DB?
What I do in similar cases is this:
I create the new field and then populate the new column in the database with the values from the old column (field).
In your case, you'd be looking at the sf_sitefinity_profile table.
This way the data will be migrated to the new field.
After that you can delete the old field and start using the new one.

Sap odata: Export a single Variable with abap

I have got a function module that counts some variables in sap system and export it as single INT4. But when I try to use this in gateway service, it says me
"no output table mapped" How can i overcome it, I tried to put this variable in a table and export then but I couldnt.
DATA: EV_ENQ TYPE STANDARD TABLE OF seqg3.
CALL FUNCTION 'ENQUEUE_READ'
EXPORTING
guname = '*'
IMPORTING
number = EV_TABLESIZE
TABLES
enq = EV_ENQ.
Ev_Tablesize is the variable that I want to export. It holds the total lock count.
Your parameter should be mapped under your service implementation in SEGW. If it is not, then you should map them again and be sure that the parameter is being displayed.

Delphi Parameterised Query won't work

I'm only a beginner in learning to use Parameterised Queries as I used to do a lot of concatentating before. I've been trying to get this query below to work. It is a simple 'Book' table, with a field called 'BookTitle'. I have a simple textbox where I invite the user to enter any title...and it should run the query below to find if that book exists. Below is my code that, when run, manages to compile. However, when an entry into the textbox is added and the button to run the query is pressed, a Debugger Exception Notification appears with the following statement.
Debugger Exception Notification: Project Project1.exe raised exception class EOleException with message 'Arguments are of the wrong type, are out of acceptable range, or are in conflict with one another'.
I then have the option to press 'Break' or 'Continue'. If I press 'Break', the line:
qbook.Parameters.ParamByName('BookTitle').DataType := ftString;
is filled with a purple/red colour (not sure what this means?).
That said, if I press 'Continue', the program will work as expected, and will continue to do so. Here is the code i've been testing.
procedure TForm4.btnRunQueryClick(Sender: TObject);
var BookEntry:string;
begin
BookEntry:=edtBookTitle.Text;
qbook.SQL.Text:='SELECT BookTitle FROM Book WHERE BookTitle = :BookTitle';
qbook.Parameters.ParamByName('BookTitle').DataType := ftString;
qbook.Parameters.ParamByName('BookTitle').Value := BookEntry;
qbook.Open;
end;
Further points to note: The components in my Delphi form are as follows
a TADOQuery named 'qbook',
a TDataSource,
a TDBGrid,
aTEdit into which the user enters their desired search criteria and
a TButton that once pressed, initiates the query.
With regards to the database, it is:
a MySQL database (Community Edition)
a table named 'Book', where BookID is the PK and is of INT data type.
a field entitled 'BookTitle' which i've set as VARCHAR(35). It is not part of the key. However, it is in the BookTitle field, that i want to apply my query.
NOTE: This answer was posted based on the original code in the question, which has been edited to match what is in my answer. See the question's revision history for the first version of the question on which my answer was based.
The solution you saw in the other post was correct; it was just for a standard TQuery and not TADOQuery. TADOQuery requires a couple of minor syntax changes:
Use Parameters.ParamByName() instead of Parameters
Set a DataType for each parameter before using it
Use .Value instead of .AsString
Here's a corrected version of your code (which also includes setting a value for BookTitle before using it.
procedure TForm4.btnRunQueryClick(Sender: TObject);
var
BookEntry:string;
begin
BookEntry := 'Some book title'; // or QueryEdit.Text or whatever
qbook.SQL.Text:='SELECT BookTitle FROM Book WHERE BookTitle = :BookTitle';
qbook.Parameters.ParamByName('BookTitle').DataType := ftString;
qbook.Parameters.ParamByName('BookTitle').Value := BookEntry;
qbook.Open;
end;
I have never known a string type query parameter need the datatype or whatever set, I would simply remove any reference to the datatype.
After all, if it hurts when you bang your head on a wall, just stop banging it.

SQL table to delphi record using BCP

I have a scenario in which I have to export data of around 500,000 records from sql table to be used in Delphi application. The data is to be loaded into a packed record. Is there a method in which i can use the BCP to write data file similar to that of writing the records to file.
As of now I am loading the data using this psudo code.
// Assign the data file generated from BCP to the TextFile object.
AssignFile(losDataFile, loslFileName);
Reset(losDataFile);
while not EOD(losDataFile) do
begin
// Read from the data file until we encounter the End of File
ReadLn(losDataFile, loslDataString);
// Use the string list comma text to strip the fields
loclTempSlist.CommaText := loslDataString;
// Load the record from the items of the string list.
DummyRec.Name := loclTempSList[0];
DummyRec.Mapped = loclTempSList[1] = 'Y';
end;
For convenience i have listed the type of Dummy rec below
TDummyRec = packed record
Name : string[255];
Mapped : Boolean;
end;
So, my question is, instead of exporting the data to a text file, will it be possible to export the data to binary so that i can read from the file directly using the record type?
like
loclFileStream := TFileStream.Create('xxxxxx.dat', fmOpenRead or fmShareDenyNone);
while loclFileStream.Position < loclFileStream.Size do
begin
// Read from the binary file
loclFileStream.Read(losDummyData, SizeOf(TDummyRec));
//- -------- Do wat ever i want.
end;
I don't have much experience on using the BCP. Please help me with this.
Thanks
Terminator...
In your record, a string[255] will create a fixed-size Ansi string (i.e. a so-called shortstring). This type is clearly deprecated, and should not be used in your code.
It will be an awful waste of space to save it directly, using a TFileStream (even if it will work). Each record will store 256 bytes for each Name.
And using a string[255] (i.e. a so-called shortstring) will make an hidden conversion to a string for most access to it. So it is not the best option, IMHO.
My advice is to use a dynamic array then serialize / unserialize it with our Open Source classes. For your storage, you can use a dynamic array. Works from Delphi 5 up to XE2. And you'll be able to use a string in the record:
TDummyRec = packed record
Name : string; // native Delphi string (no shortstring)
Mapped : Boolean;
end;
Edit after OP's comment:
BCP is just a command-line tool meant to export a lot of rows into a SQL table. So IMHO BCP is not the good candidate for your purpose.
You seems to need to import a lot of rows from a SQL table.
In this case:
Using shortstring will be in all case a waste of memory, so you'll get faster out of memory than with using a good string;
You can try our Open Source classes to retrieve all data rows one by one, then populate your records using this data: see SynDB classes - it is lighter than ADO; Then you'll be able to retrieve the record data one by one, then use our record serialization functions to create some binary content - or try a dedicated faster engine like our SynBigTable;
There are some articles about using directly the OleDB feature used by BCP from Delphi code in here - it is in french, but you can use google to translate it and here for fast bulk copy; full source code included.
You want to read a SQL-table into a record, I have no idea why you are working with the archaic AssignFile.
You should really use a TADOQuery (or suitable variant) for you database.
Put a sensible SQL-query in it; something like:
SELECT field1, field2, field3 FROM tablename WHERE .....
When in doubt you can use:
SELECT * FROM tablename
Which will select all fields from the table.
The following code will walk through all the records and all the fields and save them in a variants and save that in a FileStream.
function NewFile(Filename: string): TFileStream;
begin
Result:= TFileStream.Create(Filename, fmOpenWrite);
end;
function SaveQueryToFileStream(AFile: TFileStream; AQuery: TADOQuery): boolean;
const
Success = true;
Failure = false;
UniqueFilePrefix = 'MyCustomFileTypeId';
BufSize = 4096;
var
Value: variant;
Writer: TWriter;
FieldCount: integer;
c: integer;
RowCount: integer;
begin
Result:= Success;
try
if not(AQuery.Active) then AQuery.Open
FieldCount:= AQuery.Fields.Count;
Writer:= TWriter.Create(AFile, BufSize);
try
Writer.WriteString(UniqueFilePrefix)
//Write the record info first
Writer.WriteInteger(FieldCount);
//Write the number of rows
RowCount:= AQuery.RecordCount;
WriteInteger(RowCount);
AQuery.First;
while not(AQuery.eof) do begin
for c:= 0 to FieldCount -1 do begin
Value:= AQuery.Fields[c].Value;
Writer.WriteVariant(Value);
end; {for c}
AQuery.Next;
end; {while}
except
Result:= failure;
end;
finally
Writer.Free;
end;
end;

how to create Delphi 4 structure to map column names in XLS to column names in SQL

I have an EXCEL sheet.it has various form-fields that are named as
“smrBgm133GallonsGross/ smrBgm167GallonsGross “
and
“smrEgm133GallonsGross/ smrEgm167GallonsGross “
I added to the XCEL sheets 2 new form fields named
smrBgm167GrosGalnsDA/smrEgm167GrosGalnsDA
The above additons I made in EXCEL should ACTUALLy be named as
`smrBgm229GallonsGross/smrEgm229GallonsGross` because. This is a MUST for the Delphi application to function properly.
This Delphi-4 application extracts , and vewrifys the form DATA in tandem with the DB.
My Delphi-4 application works (checks/inserts/retrieves) so that current months beginning gallon of milk “bgm229” is equal to last months ending gallon of milk “egm229” , and then throw an exception if they are different.
Excel sheets:- Bgm167GrosGalnsDA/ Egm160GrosGalnsDA
Delphi Code (DB- input/ DB- output/validation):- bgm229/ egm229
SQL 2005 DB:- bgm167DA/ egm167DA
Actually the columns I ADDED should have been named asa "smrEgm133GallonsGross/ smrEgm167GallonsGross "...I messed up in naming them and they are on the production now....
In the Delphi procedure,for the beginning inventory, the code it is
ExtractFormBgmInfo(smrMilkAvMilk, 'smrBgm133');
ExtractFormBgmInfo(smrMilkDe, 'smrBgm167');
For ending inventory the code it is
ExtractFormEgmInfo(smrMilkAvMilk, 'smrEgm133');
ExtractFormEgmInfo(smrMilkDe, 'smrEgm167');
I am adding “smrBgm229GrosGalns/smrEgm229GrosGalns” to the list
But the issue is that they are named erroneously as “smrBgm167GrosGalnsDA/ smrEgm167GrosGalnsDA” IN THE EXCEL sheets, while they are to be named as 'smrBgm229/'smrEgm229''(as is the case in the Delphi code). Hence. I added ...to the above
ExtractFormBgmInfo(smrMilkAvMilk, 'smrBgm133');
ExtractFormBgmInfo(smrMilkDe, 'smrBgm167');
ExtractFormBgmInfo(smrMilkDyedDe, 'smrBgm229');
ExtractFormEgmInfo(smrMilkAvMilk, 'smrEgm133');
ExtractFormEgmInfo(smrMilkDe, 'smrEgm167');
ExtractFormEgmInfo(smrMilkDyedDe, 'smrEgm229');
This throws an error , as smrBgm229GallonsGross /smrEgm229GallonsGross are not defined in the EXCEL sheets .So the issue is how do I convert “smrBgm167GrosGalnsDA” from Excel sheets into “smrBgm229GallonsGross” and then make my “ExtractForm” statement correct?
Please help there is an release scheduled today and got to discuss this with my superirors
What you want to do is map one string to another. You can use a simple string list for that.
// Declare the variable somewhere, such as at unit scope or as a field
// of your form class
var
ColumnNameMap: TStrings;
// Somewhere else, such as unit initialization or a class constructor,
// initialize the data structure with the column-name mappings.
ColumnNameMap := TStringList.Create;
ColumnNameMap.Values['Bgm167 GrosGalns DA'] := 'bgm229/ egm229';
// In yet a third place in your code, use something like this to map
// the column name in your input to the real column name in your output.
i := ColumnNameMap.IndexOfName(ColumnName);
if i >= 0 then
RealColumnName := ColumnNameMap.Values[ColumnName]
else
RealColumnName := ColumnName;
Later versions of Delphi have the generic TDictionary class. Use TDictionary<string, string>. The TStrings solution I outlined above will have problems if any of the column names can have equals signs in them, but you can mitigate that by changing the NameValueSeparator property.
var
ColumnNameMap: TDictionary<string, string>;
ColumnNameMap := TDictionary<string, string>.Create;
ColumnNameMap.Add('Bgm167 GrosGalns DA', 'bgm229/ egm229');
if not ColumnNameMap.TryGetValue(ColumnName, RealColumnName) then
RealColumnName := ColumnName;