"Duplicate not allowed"

It seems there is a fundamental problem with the way the Object manager works when used in a multi-threaded application: if use the following code, i'm getting "Duplicate key values not allowed" even though all object instances are unique to the thread:


var
  ObjectManager: TObjectManager;
begin
  ObjectManager:= GetAureliusOM(ConnectionString); // this creates new instances of Connection, IDBConnection and TObjectManager
  try
    AFile := ObjectManager.Find<Tt_files>(FileID);
...
        TargetFolder := FindTargetFolder(
          AFile.f_user_ID.u_expert_ID.e_target_folder,
          AFile.f_user_ID.u_private_dir.ValueOrDefault,
          AFile.f_company.ValueOrDefault);

AFile is an entity with the f_user_ID being a foreign key:

  [Entity]
  [Table('t_files')]
  [Id('Ff_ID', TIdGenerator.IdentityOrSequence)]
  Tt_files = class
  private
    [Column('f_ID', [TColumnProp.Required, TColumnProp.NoInsert, TColumnProp.NoUpdate])]
    Ff_ID: Integer;
...
    [Association([TAssociationProp.Lazy, TAssociationProp.Required], CascadeTypeAll - [TCascadeType.Remove])]
    [JoinColumn('f_user_ID', [TColumnProp.Required], 'u_ID')]
    Ff_user_ID: Proxy<Tt_users>;
    function Getf_user_ID: Tt_users;
    procedure Setf_user_ID(const Value: Tt_users);

Apparently, for reasons that aren't clear to me, I'm getting almost constant "Duplicate key is not allowed" when hitting that code from a second thread. The duplicate object is the Tt_users instance (the two t_Files different row reference the same t_Users row)

I have no idea how to solve this.

Hello,

TMS Aurelius is thread-safe, it's the base for TMS XData servers which runs multiple threads simultaneously. 
TObjectManager object is not thread-safe. You should create and destroy one instance in each thread.
The only code you provided above should be thread-safe, as long ObjectManager instance is different for each thread. You said that, but you didn't provide the code in GetAureliusOM.
From only the code you provided, I cannot guess what's wrong. I'm not sure what you mean from "hitting that code from a second thread". Are you trying to access the same TObjectManager from a second thread?

Thank you for your answer. Here is the code that creates the Object Manager:


function GetAureliusOM(const Connection: TADOConnection; OwnedConnection: boolean): TObjectManager;
var
  DbConnection: IDBConnection;
begin
  DbConnection := TDbGoConnectionAdapter.Create(Connection, 'MSSQL2', OwnedConnection);
  result := TObjectManager.Create(DBConnection);
end;

function GetAureliusOM(const ConnectionString: String): TObjectManager; overload;
var
  Connection: TADOConnection;
begin
  Connection := TADOConnection.Create(nil);
  try
    Connection.LoginPrompt := false;
    Connection.ConnectionString := ConnectionString;
  except
    on e: exception do
    begin
      FreeAndNil(Connection);
      raise;
    end;
  end;
  result := GetAureliusOM(Connection, true);
end;

As an experiment, I have changed the code that uses the object 8and indirectly triggers the loading of the linked object) as follow:

var
  ObjectManager: TObjectManager;
  AFile: Tt_files;
  AUser: Tt_users;
begin
  ObjectManager:= GetAureliusOM(ConnectionString);
  try
    AFile := ObjectManager.Find<Tt_files>(FileID);
...
        AUser := AFile.f_user_ID;
        TargetFolder := FindTargetFolder(
          AUser.u_expert_ID.e_target_folder,
          AUser.u_private_dir.ValueOrDefault,
          AFile.f_company.ValueOrDefault);


That code doesn't seem to trigger the duplicate key arror anymore.

("MSSQL2" is a unit that fixes the problem with the support of the BIT type in MSSQL)

Are you able to build a project that reproduces that problem and can be compiled and run without 3rd party tools? 
That way we can debug and check what's wrong. That code should simply work flawlessly.

I can try to do so. This is a conversion from an existing (and old) project so I can't simply send you the source so I'll need to build something new.