1. Introduction
  2. What is EntityFactory like?
  3. Why use EntityFactory?
  4. What are the requirements and limitations of the successful use of EntityFactory?
  5. What components does EntityFactory consist of?
  6. How does EntityFactory operate?
  7. How to get started with EntityFactory?
  8. How to describe an entity correctly?
  9. How to describe an entity extension correctly?
  10. How to implement a persistent list in an entity extension?
  11. How to use entities in the code?
  12. How to use EntityFactory in criteria?
  13. How to add the extension fields to the View

Introduction

The document is intended for developers who are familiar with DevExpress XAF v13.2 and higher, and who are fluent in the terminology used with this product. The document describes the features of Xafari x06 product.

What is EntityFactory like?

EntityFactory can be described as a model of complex system design and development. It includes rules, agreements, and recommendations on the design, as well as a library of base classes and extension methods of XAF components.

Why should you use EntityFactory?

The main benefits of EntityFactory are:

  1. Simple and clear data business model.
  2. No extra "technological" business objects.
  3. The modular strategy of extending the data model.

Simple and clear data business-model

The basic concepts are Entity and Entity Extension. The main idea of EntityFactory is the way of adding new fields to application entities. While object-oriented programming (OOP) suggests solving this problem through extension inheritance from the entity, the EntityFactory solves this problem by adding extension associations to the entity.

And the use of Domain Components allows you to include the whole extension in the entity object without any additional structures.

There are no extra “technological” business objects

Using EntityFactory allows you to get rid of such "unpleasant" consequence from the use of inheritance as the emergence of new types of business objects in the application.

While using object-oriented programming (OOP), the original purpose "extension" is achieved through the creation of a "new entity." In this sense, the new class is a consequence of using the chosen technology, so it can be called "technological" (see. Figure below).

The modular strategy of data model extension

EntityFactory allows you to create any combination of the available set of extensions that may be required to the client. In doing so, conflicts of sharing "parallel" extensions that appear when using inheritance are ultimately excluded.

The figure below shows an example of a data model for entity Class1, to which seven extensions were added.

In this example, the module ExtModule2, and with it, the extension Extension2, can be safely deleted (added) in the final configuration while the application remains operational and does not require any additional rebuilding.

The figures below show a card form for Entity1 without the module with extensions

… and after adding two extensions with additional fields.


Requirements and limitations for the use of EntityFactory

Using EntityFactory assumes the following:

  • EntityFactory supports data model based on Domain Components. A data model based on XPO is not implemented in this version.
  • Entities
    • Entities can be both persistent and non-persistent
    • You can only inherit from non-persistent entities
  • Extensions of the Entity
    • Entity Extensions can be both persistent and non-persistent.
    • Persistent collections in extension are implemented in a special way
    • On default, each Extension is an Entity
    • Non-persistent extensions are mapped to the same table as the entity itself
    • Persistent extensions are stored in their own table, in doing so, associations from the Extension entity are added, and vice versa.

What components does EntityFactory consist of?

EntityFactory is placed in Xafari.dll module and contains basic interfaces and Domain Components. Extensions for Session and IObjectSpace have also been implemented for EntityFactory. EntityFactory also extends the application model with new nodes.

How does EntityFactory operate?

EntityFactory mechanism collects information about registered entities and their extensions at the application startup. After that, it builds assembly EntityAssembly.dll and adds it to the application (see Figure below).

Generated assembly comprises generated derived classes of each entity. For example, an additional Domain Component _Class1 will be created for entity Class1. These generated entities already contain all necessary connections between each other which ensure the correct operation of all use cases of EntityFactory. A calculated property Exts, the type _Entity1 is added to the entity Entity1 in an application model. This enables access to the new entity properties from View, as well as while generating various criteria of objects search.


How to get started with EntityFactory?

To start with EntityFactory you need to add Xafari.dll module. On default, EntityFactory has been activated. You can explicitly activate EntityFactory by adding the following code before initializing XafApplication.

1
Xafari.EntityFactory.Enabled = true;

How to describe an entity correctly?

To create an entity, you can use a template. An example of entity description is given below.

1
2
3
4
5
[DomainComponent]
public interface Entity1 : Xafari.Base.IEntity
{
    string String1 { get; set; }
}

To add an entity to EntityFactory, it is necessary to register it by adding a code to a module class

1
2
3
4
5
public override void Setup(ApplicationModulesManager moduleManager)
{
    base.Setup(moduleManager);
    Xafari.EntityFactory.Instance.RegisterEntity();
}

How to describe an entity extension correctly?

To create an entity extension, you can use the template. An example of entity extension description is given below.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[DomainComponent]
[EntityExtension(typeof (Entity1))]
public interface EntityExtension1 : IEntityExtension
{
    string Ext1String { get; set; }
}
public static class EntityExtension1_Extension
{
    public static EntityExtension1 EntityExtension1(this Entity1 entity)
    {
        return entity.GetExtension();
    }
    public static Entity1 Entity1(this EntityExtension1 extension)
    {
        return extension.GetEntity();
    }
}

You also need to register in EntityFactory. To do this, you must add a code to a module class

1
2
3
4
5
6
public override void Setup(ApplicationModulesManager moduleManager)
{
    base.Setup(moduleManager);
    Xafari.EntityFactory.Instance.RegisterEntity();
    Xafari.EntityFactory.Instance.RegisterExtension<Entity1, EntityExtension1>();
}

Using a static class EntityExtension1_Extension is optional. But its presence allows you to simplify work with the extensions in the code.

1
2
3
4
5
    var a = this.ObjectSpace.CreateEntity();
    var ext = a.EntityExtension1();
    ext.Ext1String = "1";
    ext.Entity1().String1 = "1";
    this.ObjectSpace.CommitChanges();

How to implement a persistence list in an entity extension?

One of the main tasks that must be solved by using the extensions is the possibility to implement persistent collections. The problem is caused by XAF stringent requirements for describing the connection 1: N or N: M. XAF does not allow you to describe in a master-class a property of the type collection with the type details-class which has no backward reference to the master-class. This requirement excludes the possibility to describe the relationship between the non-persistent classes.

On the other hand, the extension is only a "container" for the properties we want to expand the entity with, that’s why the added collection is the collection for the entity. This means that the backward reference from the collection object must point to the entity, not the extension.

The solution of the persistent collections problem with the help of Xafari is described in the following document https://galaktika-soft.com/blog/about-non-persistent-domain-components.html.

Let’s look at the example of the description of the persistent collection for extension (see. Figure). Here you can see the differences in the description of the collections: EntityExtension1 is a persistent extension, and its collection is described in a standard way; EntityExtension4 is a non-persistent extension, its collection is implemented through a link to the same entity Entity1.

To implement such a model, it is necessary to describe collections as in the example below

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
[DomainComponent]
[NonPersistentDc]
[EntityExtension(typeof (EntityExtension2))]
public interface EntityExtension4 : IEntityExtension
{
    [NonPersistentDc]
    [DevExpress.ExpressApp.DC.Aggregated]
    [BackReferenceProperty("Entity1")]
    IList Ext4Items { get; }
}
[DomainLogic(typeof (EntityExtension4))]
public class EntityExtension4Logic : DomainLogicBase
{
    public EntityExtension4Logic(EntityExtension4 instance) : base(instance) { }
    public IList Ext4Items
    {
        get { return this.GetWeakList(x => x.Ext4Items); }
    }
}
[DomainComponent]
public interface Ext4ListItem
{
    string String1 { get; set; }
    [Browsable(false)]
    Entity1 Entity1 { get; set; }
}

Key features here are description peculiarities of the property EntityExtension4.Ext4Items and its implementation in the domain logic class.
Now card form for Entity1 can be the following:


How to use entities in the code?

To work with the entities in the code, the following extensions for IObjectSpace can be used:

  • CreateEntity<>() –analogue IObjectSpace.CreateObject<>()
  • GetEntities<>() – analogue IObjectSpace.GetObjects<>()
  • FindEntity<>() – analogue IObjectSpace.FindObject<>()
  • Evaluate<>() – analogue Session.Evaluate()
  • SelectData<>() – analogue Session.SelectData()
  • SelectDataAsync<>() – analogue Session.SelectDataAsync()

EntityFactory.Instance and its methods are used for registration of entities and extensions

  • RegisterEntity<>()
  • RegisterExtension<>()

How to use EntityFactory in criteria?

Extensions properties in criteria can be used as any other entity properties.

Here are some examples for the sample of Entity1 and RefToEntity1 objects

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// select Entity1 which extension1 string property equals '1'
CriteriaOperator.Parse("EntityExtension1.Ext1String = ?", "1");
CriteriaOperator.Parse("Exts.EntityExtension1.Ext1String = ?", "1");
 
// select Entity1 which extension2 string property equals '1'
CriteriaOperator.Parse("Ext2String = ?", "1");
CriteriaOperator.Parse("Exts.Ext2String = ?", "1");
 
// select RefToEntity1 which refer to entity1 with extension1 string property equals '1'
CriteriaOperator.Parse("Entity1.EntityExtension1.Ext1String = ?", "1");
CriteriaOperator.Parse("Entity1.Exts.EntityExtension1.Ext1String = ?", "1");
 
// select RefToEntity1 which refer to entity1 with extension2 string property equals '1'
CriteriaOperator.Parse("Entity1.Ext2String = ?", "1"));
CriteriaOperator.Parse("Entity1.Exts.Ext2String = ?", "1"));
 
// select RefToEntity1 which refer to entity1 with extension1 string property equals '1'
CriteriaOperator.Parse("[][^.Entity1=This &amp;&amp; EntityExtension1.Ext1String = ?]", "1");
CriteriaOperator.Parse("[][^.Entity1=This &amp;&amp; Exts.EntityExtension1.Ext1String = ?]", "1");
 
// select RefToEntity1 which refer to entity1 with extension2 string property equals '1'
CriteriaOperator.Parse("[][^.Entity1=This &amp;&amp; Ext2String = ?]", "1");
CriteriaOperator.Parse("[][^.Entity1=This &amp;&amp; Exts.Ext2String = ?]", "1");

For details, see the example.

How to add the extension fields to the View?

Adding fields to the View entity is done in a natural way, through the use of a calculated property Exts.

Here's the view which can be obtained after adding an extension property.

Write US