The default approach to change the behavior of an existing class in Delphi is to use inheritance. However, when working with EntityDAC, inheritance can not always be applicable. In EntityDAC, to be able to use any entity class, its mapping has to be defined. Therefore, when creating new entity class descendant, you also need to define the corresponding meta-type and define the mapping for it. Such an approach is not always rational, because for minor changes in the descendant, it is necessary to write a lot of additional code.
Of course, behavior of any class can simply be changed by manually changing its code. But, using classes generated with Entity Developer, all previously made changes will be lost when the database model changes, and the classes code is completely re-generated.
In such a situation, when it is need to extend the behavior of an existing class without modifying its code, the default approach is to use class helpers. You can learn http://docwiki.embarcadero.com/RADStudio/XE5/en/Class_and_Record_Helpers for more information about class helpers in Delphi.
type TEntityHelper = class helper for TEntity ... end;
However, class helpers usage has several restrictions. For example, class helpers can not contain any instance data, class helpers can not override virtual methods etc.
EntityDAC provides its own mechanism for customizing generated entity classes, which eliminates the problem with classes re-generation and does not have disadvantages of class helpers. The main idea is to implement a class descendant with some extended functionality and "redirect" existing class mapping to the descendant class without defining new mapping for it.
Let's look at an example of the entity customization. Assume that we have the TCustomEntity class declared like shown below:
TCustomEntity = class(TMappedEntity) private FValue: TIntegerAttribute; function GetSomeValue: integer; protected procedure SetSomeValue(const Value: integer); virtual; public property SomeValue: integer read GetSomeValue write SetSomeValue; end;
Also, we have the corresponding meta-type declaration for the class, and corresponding class mapping is defined. The meta-type has the 'CustomEntity' name.
Now, suppose that we want to implement some additional logic when the Value property changes. The simplest way is to write corresponding code in the SetValue implementation. But, the class code is generated automatically by Entity Developer and will be completely re-generated when the database model changes.
So, let's declare the TCustomEntity class descendant and write desired code in the overridden SetValue method:
interface type TExtendedEntity = class(TCustomEntity) protected procedure SetSomeValue(const Value: integer); override; end; implementation procedure TExtendedEntity.SetSomeValue(const Value: integer); var NewValue: integer; begin NewValue := Value + 100; inherited SetSomeValue(NewValue); end;
Now, we have to "redirect" the TCustomEntity class mapping to the newly declared class. To do this, we use the RegisterEntityClass method of the 'CustomEntity' meta-type. Insert the following line somewhere in the application code, before first usage of the TCustomEntity class:
Where Context is the TEntityContext instance used in the application.
From now, TExtendedEntity class is mapped to the previously declared 'CustomEntity' meta-type and there is no need to declare and map a separate meta-type for it. We can test our customized entity behavior:
var Entity: TExtendedEntity; begin Context.Model['CustomEntity'].RegisterEntityClass(TExtendedEntity); Entity := Context.CreateEntity<TExtendedEntity>; Entity.SomeValue := 1; Context.Attach(Entity); ShowMessage(IntToStr(Entity.SomeValue)); // will show '101' end;
The feature is available in EntityDAC Professional and Standard editions. It is not available in EntityDAC Express Edition.