Trigger business logic
Important
It is important to understand the difference between database level triggers and these XData level triggers. A database trigger is called during changes made to the records of the table, whereas XData logic module processes the changes in the level of the data object. It must be remembered that a data object can include several database tables on the one hand and, on the other hand, a part of information regarding other objects can be stored in one table. And from this point of view, the value of such a mechanism inside the XData can hardly be overestimated!
Custom logic called over data object explicitly. But XData can call trigger logic over business valuable data object (not a single table!) on middle-ware level (no matter extracted this logic to dedicated application server or not). This logic will be called automatically when corresponded changes are applied:
- InitRepository - middle-ware trigger executed when Repository has been initialized (trigger delegate type -InitRepository<T>)
- InvalidateRepository - middle-ware trigger executed when Repository data need to be reseted (trigger delegate type -InvalidateRepository<T>)
- InvalidateObject - middle-ware trigger executed when Repository object need to be reloaded (trigger delegate type -InvalidateObject<T>)
- InitObject - middle-ware trigger executed when Repository object has been initialized (trigger delegate type -InitObject<T>)
- BeforeInsert - middle-ware trigger executed before object inserted into Repository (trigger delegate type -Trigger<T>)
- BeforeUpdate - middle-ware trigger executed before Repository object has been updated (trigger delegate type -Trigger<T>)
- BeforeDelete - middle-ware trigger executed before object has been deleted from Repository (trigger delegate type -Trigger<T>)
- AfterInsert - middle-ware trigger executed after object inserted into Repository (trigger delegate type -Trigger<T>). Skip flag is not applicable!
- AfterUpdate - middle-ware trigger executed after Repository object has been updated (trigger delegate type -Trigger<T>). Skip flag is not applicable!
- AfterDelete - middle-ware trigger executed after object has been deleted from Repository (trigger delegate type -Trigger<T>). Skip flag is not applicable!
- BeforeClear - middle-ware trigger executed before Repository has been cleared (trigger delegate type -RepositoryTrigger<T>)
- AfterClear - middle-ware trigger executed after Repository has been cleared (trigger delegate type -RepositoryTrigger<T>). Skip flag is not applicable!
Trigger delegate type - it's a method signature for middle-ware trigger handler.
public class InvoiceLogic : XDataLogic<Invoice>
{
[Action(DataActionType.AfterInsert), Action(DataActionType.AfterUpdate)]
public Trigger<Invoice> UpdateHistory =>
((ref Invoice invoice, ref DataTriggerFlag flag) =>
{
if (!invoice.CheckState(DataObjectState.New)
&& !invoice.IsChanged(x => x.DocState)) return true;
var rep = invoice.GetRepository();
using (var hist =
GetRepository<DocHistory>(rep.Layer, context: rep.Context))
{
hist.Reset()
.SetFilterValue(DocHistory.FilterByDocId,
invoice.GetProperty<long>("DocId"))
.SetFilterValue(DocHistory.FilterByDocStateId,
invoice.DocState.Key);
var newHist = hist.New();
newHist.HistoryDate = DateTime.UtcNow;
return hist.Submit(ref newHist);
}
});
[Action(DataActionType.BeforeDelete)]
public Trigger<Invoice> ClearHistory =>
((ref Invoice invoice, ref DataTriggerFlag flag) =>
{
var i = invoice;
using (var hist = GetRepository<DocHistory>(i.GetLayer(),
context: i.GetContext()))
{
return hist.Reset()
.Clear(x => x.GetProperty<long>("DocId")
== i.GetProperty<long>("DocId"));
}
});
[Action(DataActionType.BeforeClear)]
public RepositoryTrigger<Invoice> ClearHistoryBatch =>
((IRepository<Invoice> invoiceRepository, ref DataTriggerFlag flag) =>
{
using (var hist = GetRepository<DocHistory>(invoiceRepository.Layer,
context: invoiceRepository.Context))
{
return hist.Reset().Clear(x => invoiceRepository
.Any(z => x.GetProperty<long>("DocId")
== z.GetProperty<long>("DocId")));
}
});
}
Trigger and RepositoryTrigger delegates has a reference parameter of type DataTriggerFlag to specify behavior of data processing after trigger executed. There are three possible behaviors defined:
- None - Submit using default algorithm, representation layer is already refreshed
- Skip - Data submitting have completed in trigger logic or not applicable. No standard updates will called. It's a kind of "instead of" trigger logic flag.
- Refresh - Default value. Representation layer manual data refreshing is needed.
Trigger logic defined as attributed by Action attribute read only property of XDataLogic<T> class descendant. One property can be attributed as a handler for multiple triggers. Property type must to be Trigger<T> except repository based triggers (BeforeClear, AfterCLear, InitRepository or InvalidateRepository) - RepositoryTrigger<T>.