I've been looking into the source code a bit and it seems it can/should be implemented on a different level. What's needed in this case is an option to provided the CommandPerformers through attributes or the MappingExplorer. If you go to the database and fetch/perform, don't build the SQL yourself, but execute this. An example with attributes could be:
[TEntity]
[Selector(TOwnSQLSelector('exec MySpecialList'))]
[Inserter(TOwnInserter('exec InsertIntoMySpecialList :MEDIA_NAME, :FILE_LOCATION, :DURATION'))]
[Updater(TOwnUpdater('exec UpdateMySpecialList :ID, :MEDIA_NAME, :FILE_LOCATION, :DURATION'))]
[Deleter(TOwnDeleter('exec DeleteMySpecialList :ID'))]
TMediaFile = class
public
[Column('ID', [TColumnProp.Unique, TColumnProp.Required, TColumnProp.NoUpdate])]
FId: Integer;
FMediaName: string;
FFileLocation: string;
FDuration: Nullable<integer>;
public
property Id: integer read FId;
[Column('MEDIA_NAME', [TColumnProp.Required], 100)]
property MediaName: string read FMediaName write FMediaName;
[Column('FILE_LOCATION', [], 300)]
property FileLocation: string read FFileLocation write FFileLocation;
[Column('DURATION', [])]
property Duration: Nullable<integer> read FDuration write FDuration;
end;
Even a better way would be, if you could specify the database driver's name. Thus for SQL Server, execute this SQL, but for FireBird, execute this. A better option, imho. is to have this specified in code, through the MappingSetup instead of attributes, because it would get cluttered otherwise. Something like this might do:
procedure TDataModule1.CreatePerformers(ASetup: TMappingSetup);
var MediaFilePerformers: TDictionary<string, TPerformerSet>;
SQLServerPerformers: TPerformerSet;
FireBirdPerformers: TPerformerSet;
begin
MediaFilePerformers := ASetup.Performers[TMediaFile];
SQLServerPerformers := TPerformerSet.Create('SQLServer');
SQLServerPerformers.Add(pcSelect,'exec MySpecialList');
SQLServerPerformers.Add(pcInsert,'exec InsertIntoMySpecialList :MEDIA_NAME, :FILE_LOCATION, :DURATION');
SQLServerPerformers.Add(pcUpdate,'exec UpdateMySpecialList :ID, :MEDIA_NAME, :FILE_LOCATION, :DURATION');
SQLServerPerformers.Add(pcDelete,'exec DeleteMySpecialList :ID');
SQLServerPerformers := TPerformerSet.Create('FireBird');
SQLServerPerformers.Add(pcSelect,'execute procedure MySpecialList');
SQLServerPerformers.Add(pcInsert,'execute procedure InsertIntoMySpecialList :MEDIA_NAME, :FILE_LOCATION, :DURATION');
SQLServerPerformers.Add(pcUpdate,'execute procedure UpdateMySpecialList :ID, :MEDIA_NAME, :FILE_LOCATION, :DURATION');
SQLServerPerformers.Add(pcDelete,'execute procedure DeleteMySpecialList :ID');
MediaFilePerformers.Add('SQLServer',SQLServerPerformers);
MediaFilePerformers.Add('FireBird', FireBirdPerformers);
TMappingExplorer.ReplaceDefaultInstance(TMappingExplorer.Create(ASetup));
...
end;
That opens up the possibility to have execution of stored procedures on a class and have different executions per database type. But that also removes the option(s) to do search criteria on a SQL level or the option of foreign keys on this entity. Thus it comes with consequences. You can't use this class for criteria searches or join it with another entity (since Aurelius joins on SQL level, not on object level). Maybe it might be better not to call it an entity, but a (let's say) derived-entity.
Consider this: suppose you work in a bank and the DBA denies you direct access to the tables, because he wants to audit every interaction with the database. But you can fetch or manipulate data through stored procedures or views (And remeber that not all views are updatable). That setup makes Aurelius unusable.
Suppose the generated SQL performs badly and rewriting the SQL in another way increases performace by x%. This is an everyday situation of a developer. Denying access to the SQL, if needed, doesn't sound like a key feature at that point, but more like a nuisance.
The key feature of an ORM is to convert datasets to objectlists and back. How you get to those datasets, should be irrelevant. Whether the dataset comes from a simple select on one table, a select with a join on multiple tables or a stored procedure, should not matter. Your approach limits the programmer by denying control over the SQL. It's OK to have sql generation, because in most cases, it is trivial, but there are cases where this is not an option, like database privileges and performance. I understand you see SQL generation as a key feature, true, but it should not be obligated. By allowing SQL to be rewrittin, you open up the flexibility of the ORM.