eXtensions Framework. Definition and Registration

This topic illustrates how to implement Entities and Extensions. To get full results, the Entities and Extensions should be registered, this is described in the corresponding section. To be specific, the base module will be called the Core, and a custom module - XCRM.

To use Entities and Extensions in the project, it is required to add Xafari.XF module (Xafari.XF.dll assembly).

Define Entity

The base Core module contains definition for the two Entities: Person and Contact inherited from the Person.

  • c#
  • VB

[DomainComponent]
[NonPersistentDc]
public interface Person : IXFEntity
{
  string LastName { get; set; }
  string FirstName { get; set; }
  [Calculated("concat(isnull(FirstName, ''), ' ', isnull(LastName, ''))")]
  string FullName { get; }
}
[DomainComponent]
public interface Contact : Person
{
  string Phone { get; set; }
}

<DomainComponent> _
<NonPersistentDc> _
Public Interface Person
  Inherits IXFEntity
  Property LastName As String
  Property FirstName As String
  <Calculated("concat(isnull(FirstName, ''), ' ', isnull(LastName, ''))")> _
ReadOnly Property FullName As String
End Interface
<DomainComponent> _
Public Interface Contact
  Inherits Person
  Property Phone As String
End Interface

The custom XCRM module implements the Customer Entity, which inherited from the Person and contains persistent collection of the Contact objects.

  • c#
  • VB

[DomainComponent]
public interface Customer : Person
{
  string Name { get; set; }
  [NonPersistentDc]
  [BackReferenceProperty("Exts.Customer.Customer")]
  IList<Contact> Contacts { get; }
}
[DomainLogic(typeof(Customer))]
public class CustomerLogic : DomainLogicBase<Customer>
{
  public CustomerLogic(Customer instance)
    : base(instance)
  {
  }
  public IList<Contact> Contacts
  {
    get
    {
      return this.GetWeakList(x => x.Contacts);
    }
  }
}

<DomainComponent> _
Public Interface Customer
  Inherits Person
  Property Name As String
  <NonPersistentDc> _
<BackReferenceProperty("Exts.Customer.Customer")> _
ReadOnly Property Contacts As IList(Of Contact)
End Interface
<DomainLogic(GetType(Customer))> _
Public Class CustomerLogic
  Inherits DomainLogicBase(Of Customer)
  Public Sub New(ByVal instance As Customer)
    MyBase.New(instance)
  End Sub
  Public ReadOnly Property Contacts As IList(Of Contact)
    Get
      Return Me.GetWeakList(Function(ByVal x) x.Contacts)
    End Get
  End Property
End Class

To add a new Entity to the project, use a special VS template from the Xafari Templates Gallery

extensions_framework_14

Define Extension

Add Extensions to the XCRM module. Code snippet below describes Extensions for the Person and Contact Entities.

  • c#
  • VB

[DomainComponent]
[NonPersistentDc]
[EntityExtension(typeof(Contact))]
public interface XContact_Address : IXFEntityExtension
{
  string Country { get; set; }
  string City { get; set; }
  string Address { get; set; }
}
[DomainComponent]
[NonPersistentDc]
[EntityExtension(typeof(Person))]
public interface XPerson_Titles : IXFEntityExtension
{
  string Title { get; set; }
}
[DomainComponent]
[EntityExtension(typeof(Contact))]
public interface XContact_CustomerInfo : IXFEntityExtension
{
  Customer Customer { get; set; }
}

<DomainComponent> _
<NonPersistentDc> _
<EntityExtension(GetType(Contact))> _
Public Interface XContact_Address
  Inherits IXFEntityExtension
  Property Country As String
  Property City As String
  Property Address As String
End Interface
<DomainComponent> _
<NonPersistentDc> _
<EntityExtension(GetType(Person))> _
Public Interface XPerson_Titles
  Inherits IXFEntityExtension
  Property Title As String
End Interface
<DomainComponent> _
<EntityExtension(GetType(Contact))> _
Public Interface XContact_CustomerInfo
  Inherits IXFEntityExtension
  Property Customer As Customer
End Interface

It is recommended to use a special static class with each Extension. This technique will provide you with a simple work with Extension in code. See, for example, XContact_CustomerInfo_Extension static class below.

  • c#
  • VB

public static class XContact_CustomerInfo_Extension
{
  public static XContact_CustomerInfo CustomerInfo(this Contact entity)
  {
    return entity.GetExtension<XContact_CustomerInfo>();
  }
  public static Contact Contact(this XContact_CustomerInfo extension)
  {
    return extension.GetEntity<Contact>();
  }
}
public static class XContact_Address_Extension
{
  public static XContact_Address Address(this Contact entity)
  {
    return entity.GetExtension<XContact_Address>();
  }
  public static Contact Contact(this XContact_Address extension)
  {
    return extension.GetEntity<Contact>();
  }
}
public static class XPerson_Titles_Extension
{
  public static XPerson_Titles Titles(this Person entity)
  {
    return entity.GetExtension<XPerson_Titles>();
  }
  public static Person Person(this XPerson_Titles extension)
  {
    return extension.GetEntity<Person>();
  }
}

Public Module XContact_CustomerInfo_Extension
  <System.Runtime.CompilerServices.Extension> _
Public Function CustomerInfo(ByVal entity As Contact) As XContact_CustomerInfo
    Return entity.GetExtension(Of XContact_CustomerInfo)()
  End Function
  <System.Runtime.CompilerServices.Extension> _
Public Function Contact(ByVal extension As XContact_CustomerInfo) As Contact
    Return extension.GetEntity(Of Contact)()
  End Function
End Module
Public Module XContact_Address_Extension
  <System.Runtime.CompilerServices.Extension> _
Public Function Address(ByVal entity As Contact) As XContact_Address
    Return entity.GetExtension(Of XContact_Address)()
  End Function
  <System.Runtime.CompilerServices.Extension> _
Public Function Contact(ByVal extension As XContact_Address) As Contact
    Return extension.GetEntity(Of Contact)()
  End Function
End Module
Public Module XPerson_Titles_Extension
  <System.Runtime.CompilerServices.Extension> _
Public Function Titles(ByVal entity As Person) As XPerson_Titles
    Return entity.GetExtension(Of XPerson_Titles)()
  End Function
  <System.Runtime.CompilerServices.Extension> _
Public Function Person(ByVal extension As XPerson_Titles) As Person
    Return extension.GetEntity(Of Person)()
  End Function
End Module

Code snippet below demonstrates how to use implemented static class.

  • c#
  • VB

public void CreatePersonObject()
{
  var person = ObjectSpace.Xafari().CreateObject<Person>();
  // default usage
  person.GetExtension<XPerson_Titles>().Title = "Mr.";
  // static extensions usage
  person.Titles().Title = "Mr.";
}

Public Sub CreatePersonObject()
  Dim person = ObjectSpace.Xafari().CreateObject(Of Person)()
  ' default usage
  person.GetExtension(Of XPerson_Titles)().Title = "Mr."
  ' static extensions usage
  person.Titles().Title = "Mr."
End Sub

Important

It is necessarily to use static methods when using LINQ (see Manipulations topic).

To add a new Extension to the project, use a special VS template from the Xafari Templates Gallery.

extensions_framework_15

Registration

In fact, the developer is only required to decorate the Entities and Extensions with a special attributes. The framework will register these types properly.

RegisterEntityAttribute. This attribute is intended to register the Entity:

  • example

[RegisterEntity]
 public interface DC1 : IXFEntity {}

RegisterExtensionAttribute. This attribute is intended to register the Extension:

  • example

[RegisterExtension(typeof(DC1))]
 public interface Ext1 : IXFEntityExtension {}

NonXFEntityAttribute. Use this attribute when a new persistent Entity is the heir of the base persistent Entity. In this situation, the system will issue an exception and require the use of SharedPart. Apply the NonXFEntityAttribute to the base Entity it will work correctly.

Note

The described technique is applicable for both eXtensions Framework Entities and XAF Entities (i.e. Domain Components)

Once the module containing the marked Entities and Extensions will be added to the application, the framework will scan the module, detect the required types and register them. This method of registration can be applied both to XFEntity and XafEntity (i.e. regular Domain Components).

There is a possibility to specify the necessary types in special enumeration explicitly. For this it is required that the module class has implemented the Xafari.ITypesProvider<T> interface. You can apply this technique if you are knowledgeable in the data model and you are sure you don't miss anything. But this has a positive impact on performance.

Explicit Registration

This section not required, it describes the internal mechanisms for the registration of Entities and Extensions. In earlier versions of Xafari, registration was performed only in this way. It was necessary to call a special methods in the class of each module that contains Entities or Extensions. Since х011 these functions are performed automatically and it may not be necessary. It is enough to do manipulations described in the previous section.

To register Entities you need to support Xafari.XF.IXFRegistrator interface in module by implementing RegisterXF() method. Code snippet below demonstrates Entities registration in Core module.

  • c#
  • VB

public class CoreModule : ModuleBase, IXFRegistrator
{
  void IXFRegistrator.RegisterXF(EntityFactory entityFactory)
  {
    this.RegisterEntity<Person>();
    this.RegisterEntity<Contact>();
  }
}

Public Class CoreModule
  Inherits ModuleBase
  Implements IXFRegistrator
  Private Sub RegisterXF(ByVal entityFactory As EntityFactory) Implements IXFRegistrator.RegisterXF
    Me.RegisterEntity(Of Person)()
    Me.RegisterEntity(Of Contact)()
  End Sub
End Class

Extensions registrationn in XCRM module:

  • c#
  • VB

public class XCRMModule : ModuleBase, IXFRegistrator
{
  void IXFRegistrator.RegisterXF(EntityFactory entityFactory)
  {
    this.RegisterEntity<Customer>();
    this.RegisterExtension<Contact, XContact_Customer>(a => a.Customer(), b => b.Contact());
    this.RegisterExtension<Contact, XContact_Address>(a => a.Address(), b => b.Contact());
    this.RegisterExtension<Person, XPerson_Titles>(a => a.Titles(), b => b.Person());
  }
}

Public Class XCRMModule
  Inherits ModuleBase
  Implements IXFRegistrator
  Private Sub RegisterXF(ByVal entityFactory As EntityFactory) Implements IXFRegistrator.RegisterXF
    Me.RegisterEntity(Of Customer)()
    Me.RegisterExtension(Of Contact, XContact_Customer)(Function(ByVal a) a.Customer(), Function(ByVal b) b.Contact())
    Me.RegisterExtension(Of Contact, XContact_Address)(Function(ByVal a) a.Address(), Function(ByVal b) b.Contact())
    Me.RegisterExtension(Of Person, XPerson_Titles)(Function(ByVal a) a.Titles(), Function(ByVal b) b.Person())
  End Sub
End Class

Note

RegisterEntity method also register DC with the same name as the name of the registered type. There are two optional parameters to manage Entity table name: namespace is a prefix for table names in the database, it is used to group tables, and also to ensure uniqueness of table names. By default, contains an empty string; entityName is used as the table name in the database. By default, it the same name as the type. RegisterExtension method also register Extension as Entity.

You can pass lambda-expression to the RegisterEntity method, this expression defines the name of the property to bind Entity and Extension (see Persistent and non persistent Entities and Extensions). This is necessary if you plan to LINQ (see Operations).

Is it possible that the structure of the Extension is very complex and includes other Entities. Then DX can generate an exception with the recommendation on the use of Shared Parts. In this situation it is necessary to use the RegisterExtension2 method, which makes registration taking into account inheritance from other Entities.