Hello,
I'm not quite sure, where the problem is - in the client or in the server. I have the following scenario:
I'd
like to load multiple tables at application start in generic lists. It
works fine when loading one after the other, but when I do this in tasks
(threads) I get exceptions, memory leaks and error messages. For
multithreading I use the OmniThreadLibrary in the client - but I do not
think that the problem is related to this library.
My Server looks like this:
SparkleServer := THttpSysServer.Create;
lConnectionFactory := TDBConnectionFactory.Create(
function: IDBConnection
var
lConn: TUniConnection;
begin
lConn := TUniConnection.Create(nil);
// initialization of the connection values for TUniConnection incl. LoginPrompt := false
hsCreateIniFile.ReadUniConnection('Ac5Settings', lConn);
Result := TUniDacConnectionAdapter.Create(lConn, 'MySql', true);
end
);
Module := TXDataServerModule.Create(
'http://+:2001/ac5/v1/api',
TDBConnectionPool.Create(5, lConnectionFactory)
);
An in my client the code for one of the tasks looks like this:
var
FLookupTableStudium: TList<Tac5Studium>;
procedure Tdm.LoadLookupTableStudium;
begin
CreateTask(
procedure(const task: IOmniTask)
var
lClient: TXDataClient;
begin
lClient := TXDataClient.Create;
try
lClient.ReturnedInstancesOwnership := TInstanceOwnership.None;
lClient.Uri := lIni.ReadString('Ac5RestSettings', 'Url', 'http://localhost:2001/ac5/v1/api');
FLookupTableStudium := lClient.List<Tac5Studium>;
finally
lClient.Free;
end;
end)
.OnTerminated(procedure(const task: IOmniTaskControl)
ShowMessage(format('Studium geladen - count: %d', [FLookupTableStudium.Count]));
end)
.Run;
end;
As I told, everything works fine when I run these tasks with enough time between
LoadLookupTableStudium;
sleep(1000);
LoadLookupTableKlasse; // very similar to LoadLookupTableStudium
But if I run them without sleep, the second one crashes...
Maybe
this information is already enough to show what I am doing wrong? I
experimented already a few hours but am not able to find my error.
I would be really glad if You could give me a hint.
Regards
Harald
Hello Harald,
var E: TMappingExplorer;
C: TClass;
begin
E := TMappingExplorer.Default;
for C in E.Hiearchy.Classes do
begin
E.GetTable(C);
E.GetId(C);
E.GetVersionColumn(C);
E.GetAssociations(C, False, False);
E.GetAssociations(C, False, True);
E.GetAssociations(C, True, False);
E.GetAssociations(C, True, True);
E.GetColumns(C, False, False);
E.GetColumns(C, False, True);
E.GetColumns(C, True, False);
E.GetColumns(C, True, True);
E.GetDiscriminatorColumn(C, False);
E.GetDiscriminatorColumn(C, True);
E.GetSequence(C, False);
E.GetSequence(C, True);
E.GetClassStateMembers(C, False, False);
E.GetClassStateMembers(C, False, True);
E.GetClassStateMembers(C, True, False);
E.GetClassStateMembers(C, True, True);
E.GetClassVisibleMembers(C, False);
E.GetClassVisibleMembers(C, True);
end;
Hello Wagner,
thanks for Your answer and the code. I have trouble to run this code. First TMappingExplorer was not found and then I put Aurelius.Mapping.Explorer into uses. But now the code still does not compile E.Hierarchy is not declared.
Regards
Harald
Hello Wagner,
I just discovered the typo in Your code
I changed
and it compiles.
Great - and my errors and AVs are gone. What does this code do? What did I miss?
Regards
Harald
TMappingExplorer loads its information on demand. And such mechanism is not thread-safe. That code makes sure that everything is loaded in advance, then it's thread-safe.
Thanks. Thread problem is solved. Working well.
Is this necessary anymore?
I think MappingExplorer is calling LoadMapping once, so I think you could speed it up by using this:
for hClass in MappingExplorer.Hierarchy.Classes do
begin
MappingExplorer.FindAbstractEntityTypeFromClass(hClass);
break;
end;
right?
Probably it can be replaced by the mentioned code, yes.
That's fine, because if you have a lot of Entities in this Explorer, this is a lot overhead for doing nothing upon second iteration.