XData.Aurelius incompatible?

Hi

I was playing around with Aurelius with XData what looks like a good combination.

I tested a model with Aurelius = webform which works and tested the same with Aurelius + XData which does not work.

Exception: Association not found for member "TCategoriesInMember.FAppMemberId"


It looks like the Modelbuilder in  XData (XData.Aurelius.ModelBuilder) is a different one? This does not seem right. 


I hope you can help!





Below the models:

Works with only Aurelius:
=========================

unit AppControlModel;

interface

uses
SysUtils,
Generics.Collections,
Aurelius.Mapping.Attributes,
Aurelius.Types.Blob,
Aurelius.Types.DynamicProperties,
Aurelius.Types.Nullable,
Aurelius.Types.Proxy;

type

TCategoriesInMember = class;
TAppMember = class;
TCategory = class;

[Entity]
[Automapping]
[UniqueKey('Name')]
[Table('AppMembers')]
[Id('FID', TIdGenerator.IdentityOrSequence)]
TAppMember = class
private
[Column('ID', [TColumnProp.Required, TColumnProp.NoInsert,
TColumnProp.NoUpdate])]
FId: Integer;
FName: string;
FMemberControlId: Integer;
FHasApp: Boolean;

[ManyValuedAssociation([TAssociationProp.Lazy, TAssociationProp.Required],
[TCascadeType.SaveUpdate, TCascadeType.Merge], 'FAppMemberId')]
FAppMemberCategoryList: Proxy<TList<TCategoriesInMember>>;
function GetAppMemberCategoryList: TList<TCategoriesInMember>;

public

property AppMemberCategoryList: TList<TCategoriesInMember>
read GetAppMemberCategoryList;

property Id: Integer read FId write FId;
property Name: string read FName write FName;
property HasApp: Boolean read FHasApp write FHasApp;
property MemberControlId: Integer read FMemberControlId
write FMemberControlId;
end;

[Entity]
[Automapping]
[Table('Categories')]
[UniqueKey('Name')]
[Id('FID', TIdGenerator.IdentityOrSequence)]
TCategory = class
private
[Column('ID', [TColumnProp.Required, TColumnProp.NoInsert,
TColumnProp.NoUpdate])]
FId: Integer;
FName: string;
public
property Name: string read FName write FName;
property Id: Integer read FId write FId;
end;

[Entity]
[Table('AppMemberCategory')]
[Id('FCategoryId', TIdGenerator.None)]
[Id('FAppMemberId', TIdGenerator.None)]
TCategoriesInMember = class
private
[JoinColumn('AppMemberId', [TColumnProp.Required], 'ID')]
FAppMemberId: TAppMember;

[Association([TAssociationProp.Lazy, TAssociationProp.Required],
CascadeTypeAll - [TCascadeType.Remove])]
[JoinColumn('CategoryId', [TColumnProp.Required], 'ID')]
FCategoryId: Proxy<TCategory>;

function GetCategoryId: TCategory;
procedure SetCategoryId(const Value: TCategory);
public
  property AppMemberId: TAppMember read FAppMemberId write FAppMemberId;
property CategoryId: TCategory read GetCategoryId write SetCategoryId;
end;

implementation

function TCategoriesInMember.GetCategoryId: TCategory;
begin
Result := FCategoryId.Value;
end;

procedure TCategoriesInMember.SetCategoryId(const Value: TCategory);
begin
FCategoryId.Value := Value;
end;

{ TAppMember }

function TAppMember.GetAppMemberCategoryList: TList<TCategoriesInMember>;
begin
result := FAppMemberCategoryList.Value;
end;

initialization

RegisterEntity(TAppMember);
RegisterEntity(TCategory);
RegisterEntity(TCategoriesInMember);

finalization

end.

--------------------------------------------------------------------------------------------------------------------------

Works with Aurelius + XData:
============================

unit AppControlModel;

interface

uses
SysUtils,
Generics.Collections,
Aurelius.Mapping.Attributes,
Aurelius.Types.Blob,
Aurelius.Types.DynamicProperties,
Aurelius.Types.Nullable,
Aurelius.Types.Proxy;

type

TCategoriesInMember = class;
TAppMember = class;
TCategory = class;

[Entity]
[Automapping]
[UniqueKey('Name')]
[Table('AppMembers')]
[Id('FID', TIdGenerator.IdentityOrSequence)]
TAppMember = class
private
[Column('ID', [TColumnProp.Required, TColumnProp.NoInsert,
TColumnProp.NoUpdate])]
FId: Integer;
FName: string;
FMemberControlId: Integer;
FHasApp: Boolean;

[ManyValuedAssociation([TAssociationProp.Lazy, TAssociationProp.Required],
[TCascadeType.SaveUpdate, TCascadeType.Merge], 'FAppMemberId')]
FAppMemberCategoryList: Proxy<TList<TCategoriesInMember>>;
function GetAppMemberCategoryList: TList<TCategoriesInMember>;

public

property AppMemberCategoryList: TList<TCategoriesInMember>
read GetAppMemberCategoryList;

property Id: Integer read FId write FId;
property Name: string read FName write FName;
property HasApp: Boolean read FHasApp write FHasApp;
property MemberControlId: Integer read FMemberControlId
write FMemberControlId;
end;

[Entity]
[Automapping]
[Table('Categories')]
[UniqueKey('Name')]
[Id('FID', TIdGenerator.IdentityOrSequence)]
TCategory = class
private
[Column('ID', [TColumnProp.Required, TColumnProp.NoInsert,
TColumnProp.NoUpdate])]
FId: Integer;
FName: string;
public
property Name: string read FName write FName;
property Id: Integer read FId write FId;
end;

[Entity]
[Table('AppMemberCategory')]
[Id('FCategoryId', TIdGenerator.None)]
[Id('FAppMemberId', TIdGenerator.None)]
TCategoriesInMember = class
private
[Association([TAssociationProp.Lazy, TAssociationProp.Required],
CascadeTypeAll - [TCascadeType.Remove])]

[JoinColumn('AppMemberId', [TColumnProp.Required], 'ID')]
FAppMemberId: Proxy<TAppMember>;

[Association([TAssociationProp.Lazy, TAssociationProp.Required],
CascadeTypeAll - [TCascadeType.Remove])]
[JoinColumn('CategoryId', [TColumnProp.Required], 'ID')]
FCategoryId: Proxy<TCategory>;

function GetCategoryId: TCategory;
function GetAppMemberId: TAppMember;

procedure SetCategoryId(const Value: TCategory);
procedure SetAppMemberId(const Value: TAppMember);
public
property AppMemberId: TAppMember read GetAppMemberId write SetAppMemberId;
property CategoryId: TCategory read GetCategoryId write SetCategoryId;
end;

implementation

procedure TCategoriesInMember.SetAppMemberId(const Value: TAppMember);
begin
FAppMemberId.Value := Value;
end;

procedure TCategoriesInMember.SetCategoryId(const Value: TCategory);
begin
FCategoryId.Value := Value;
end;

{ TAppMember }

function TAppMember.GetAppMemberCategoryList: TList<TCategoriesInMember>;
begin
result := FAppMemberCategoryList.Value;
end;

function TCategoriesInMember.GetAppMemberId: TAppMember;
begin
result := FAppMemberId.Value;
end;

function TCategoriesInMember.GetCategoryId: TCategory;
begin
result := FCategoryId.Value;
end;

initialization

RegisterEntity(TAppMember);
RegisterEntity(TCategory);
RegisterEntity(TCategoriesInMember);

finalization

end.

 
 
 
 

Hi Edward, 

I don't understand exactly what the problem is. The second mapping model indeed has the needed [Association] attribute on FAppMemberId which the first one doesn't have.
If the second model works on both Aurelius and XData, why don't you just use it?
Wagner

Hi Wagner,


Thanks for answering.  It is because the first one produces better SQL.  It saves one join.

Edward




Hi Wagner,


Another reason, as I mentioned is that the other raises an exception while the Aurelius project is working as expected.

I'm confused. First, forget about the first mapping. It's not a valid mapping.

Let's work on the second one. Since the mapping configured FAppMemberId as lazy, it would not add a join on that. 
Also, what is the error message you get? Could you please provide the steps to reproduce the issue?

Hi Wagner,


I'm not getting an error on the second one. Only on the first one.

The first one should be valid because in a many to many scenario (or better a member collection scenario) you can go one way only. For example: I'm asking a member which category collection it has. There is no point to query the member because I already know the member. 
Of course on the collection side I could optionally implement the same kind of mapping.


  




'Of course on the collection side I could optionally implement the same kind of mapping.'


should be:

'Of course on the category side I could optionally implement the same kind of mapping.'

I really don't understand what you said. Both mappings are "equal" in the same they have the same model. They have an association named AppMemberId. 

The difference is that the first mapping is wrong and the second mapping is correct, implemented with lazy-loading. 
I can't see what the relation is with many-to-many associations.

In Aurelius, to query objects by one value of their associations, even by id, you must use CreateAlias and then query by any property of the association:


.CreateAlias('AppMemberId', 'appid')
.Where(Linq['appid.id'] = 5)