ATF.Repository - is an object-oriented data access technology. It is an object-relational mapping (ORM) solution for bpm`online from Advanced Technologies Foundation.
This is an external library and not a part of bpm`online kernel.
- working with data via models;
- building direct and reverse data dependencies via models;
- creating, modifying and deleting data with the help of models with business logic implementation.
Repository (ATF.Repository.Repository) - is a storage and model generator. All models should be created via the repository. All changes are applied via the repository.
var repository = ClassFactory.Get<IRepository>();
repository.UserConnection = UserConnection;
repository.Save();
Model - basic unit of data modeling. It is connected to the Entity. The model is inherited from an abstract BaseModel class (ATF.Repository.BaseModel). It is marked with the Schema attribute (ATF.Repository.Attributes.Schema). Model properties, connected to the Entity fields, are marked with SchemaProperty attribute (ATF.Repository.Attributes.SchemaProperty).
Attention! The type of property must be the same as the type of data in connected column.
Note. It is not required that the title of the model and its properties matches the title of the schema and its fields.
[Schema("TsOrderExpense")]
public class Expense : BaseModel {
// Connection with the "Type" lookup field
[SchemaProperty("Type")]
public Guid TypeId { get; set; }
// Connection with the "ExpenseDate" Date-Time field
[SchemaProperty("ExpenseDate")]
public DateTime ExpenseDate { get; set; }
// Connection with the "Amount" decimal field
[SchemaProperty("Amount")]
public decimal Amount { get; set; }
}
To set up direct connection, add a property of a model type to the model and mark it with the LookupProperty attribute (ATF.Repository.Attributes.LookupProperty).
[Schema("TsOrderExpense")]
public class Expense : BaseModel {
// Connection with the "Order" lookup field
[SchemaProperty("Order")]
public Guid OrderId { get; set; }
// Setting up direct connection with the Order model, using the value of "Order" lookup field
[LookupProperty("Order")]
public virtual Order Order { get; set; }
}
[Schema("TsOrder")]
public class Order : BaseModel {
// Connection with the "Amount" Decimal field
[SchemaProperty("Amount")]
public decimal Amount { get; set; }
}
var amount = expenceBonus.Order.Amount;
To set up reverse connection, add a property of List<T>
type to a master model, where "T" states for a detail model.
[Schema("TsOrderExpense")]
public class Expense : BaseModel {
// Setting up reverse connection with the ExpenseProduct model, using the name of detail entity schema column for link.
[DetailProperty("TsOrderExpense")]
public virtual List<ExpenseProduct> ExpenseProducts { get; set; }
}
[Schema("TsOrderExpenseProduct")]
public class ExpenseProduct : BaseModel {
//Entity schema TsOrderExpenseProduct contain column TsOrderExpense
//but we shouldn't add property with map on that column if we want to create reverse connection
// Connection with the "Amount" Decimal field
[SchemaProperty("Amount")]
public decimal Amount { get; set; }
}
var expenseProducts = expense.ExpenseProducts.Where(x => x.Amount > 100m);
A model is created by calling a CreateItem<T>
method and specifying the model type. Upon that, properties, connected to the Entity, will be populated with default values.
var bonusModel = repository.CreateItem<Bonus>();
Existing model is read by means of calling a GetItem<T>
method, where Id - is the identifier of the existing record.
var bonusModel = Repository.GetItem<Bonus>(Id);
bonusModel.Amount = 100m;
Model instance is deleted by calling DeleteItem<T>
method, where model - is the instance to be deleted.
Repository.DeleteItem<Bonus>(model);
Models setup allows lazy loading of models by direct and indirect connections. To launch lazy loading add virtual modifier to the property.
In the following example values of Order and Products properties will be loaded at once. Values of Document and Expenses properties will be loaded at the moment of the first applying.
Note. If possible, lazy loading is recommended.
[Schema("TsOrderExpense")]
public class Invoice : BaseModel {
[LookupProperty("Document")]
public virtual Document Document { get; set; }
[LookupProperty("Order")]
public Order Order { get; set; }
[DetailProperty("InvoiceId")]
public virtual List<Expense> Expenses { get; set; }
[DetailProperty("InvoiceId")]
public List<InvoiceProduct> Products { get; set; }
}
Working with models does not exclude usage of data access basic mechanisms - both via EntitySchemaQuery (Terrasoft.Core.Entities.EntitySchemaQuery) and Select (Terrasoft.Core.DB.Select).
These approaches are shown in the following example:
[Schema("TsOrderExpense")]
public class Expense : BaseModel {
public decimal BonusProductAmountSumm() {
var select = new Select(UserConnection)
.From("BonusProduct")
.Column(Func.Sum("Amount"))
.Where("Id").IsEqual(new QueryParameter(Id)) as Select;
return select.ExecuteScalar<decimal>();
}
public decimal BonusProductPrimaryAmountSymm() {
var esq = new EntitySchemaQuery(UserConnection.EntitySchemaManager, "BonusProduct");
var primaryAmountColumnName = esq.AddColumn(esq.CreateAggregationFunction(AggregationTypeStrict.Sum, "PrimaryAmount"));
var collection = esq.GetEntityCollection(UserConnection);
return collection.Count > 0
? collection[0].GetTypedColumnValue<decimal>(primaryAmountColumnName.Name)
: 0m;
}
}