XAF – The State of Domain Components Technology in v2011 Vol 1

This post may be outdated. For the latest Domain Components concepts and examples refer to the current online documentation.

We are happy to announce that in v2011 vol1 the Domain Components (DC) technology leaves CTP and reaches the Beta stage. During this release, XAF and XPO teams  invested significant resources in fixing known issues and covering more scenarios. While doing this, we have rewritten the old mechanism of persistent interface entities generation.

Registering entities As Alias

One of the key features of this rewrite is a new entities registration mode - so-called AsAlias mode. It is important for this blog to remind you what  an “entity” is in terms of DC. Here and in the future, by “entity” we mean a persistent interface or domain component, representing a final business entity (business model if you want). Although, domain components are often composed of several components (sorry for the tautology), not every domain component can be called an “entity”. This is again only the registered domain component used in your final application. I hope that now, we are done with the terms and can continue.clip_image002

Registering an entity as alias means that during the code generation, a single implementation class will be physically generated for it. Hence, all queries to XPO from this class will be served as for a regular XPO class. Furthermore, only one table will be created in the database for such entity! Let’s demonstrate this with the help of a concrete example.

I think that is enough theory for now. I will take a test case from one of my Code Central examples (E2829 - How to generate and assign a sequential number for a business object within a database transaction, while being a part of a successful saving process) and describe it more easily:

  1: using DevExpress.ExpressApp.DC;
  2: using DevExpress.Persistent.Base;
  3: using DevExpress.Persistent.Validation;
  4: 
  5: namespace GenerateUserFriendlyId.Module.BO {
  6:     public interface ISupportSequentialNumber {
  7:         long SequentialNumber { get; set; }
  8:     }
  9:     [DomainComponent]
 10:     public interface IBaseDomainComponent : ISupportSequentialNumber  { }
 11: 
 12:     [DefaultClassOptions]
 13:     [DomainComponent]
 14:     [XafDefaultProperty("Title")]
 15:     [ImageName("BO_Note")]
 16:     public interface IDocument : IBaseDomainComponent {
 17:         [Calculated("concat('D', ToStr(SequentialNumber))")]
 18:         string DocumentId { get; }
 19:         [RuleRequiredField("IDocument.Title.RuleRequiredField", DefaultContexts.Save)]
 20:         [FieldSize(255)]
 21:         string Title { get; set; }
 22:         [FieldSize(8192)]
 23:         string Text { get; set; }
 24:     }
 25: }

As you see, here I have one base domain component – IBaseDomainComponent, and another one – IDocument, descending from it (ISupportSequentialNumber is not domain component and just a pure interface, which we will not discuss here).

Previously, if I had registered my IDocument component:

  1: ...
  2: public override void Setup(XafApplication application) {
  3:     base.Setup(application);
  4:     if (!XafTypesInfo.IsInitialized) {
  5:         XafTypesInfo.Instance.AddEntityToGenerate("Document", typeof(IDocument), typeof(BasePersistentObject));
  6:     }
  7: }
  8: ...
  9: [NonPersistent]
 10: public abstract class BasePersistentObject : BaseObject, ISupportSequentialNumber { ... }
 11: ...

I would have received the following database structure:

clip_image004

Take special note that 5 tables would have been generated in this situation:

  • a single table for a registered entity (dbo.Document);
  • two separate tables to hold data of each domain component (dbo.IBaseDomainComponentClass & dbo.IDocumentClass);
  • two link tables used to establish relations between domain component data and entities (these are the expanded dbo.IBaseDomainComponentClassDocument and dbo.IDocumentClassDocument).

At first glance, this may look like overkill for such a trivial case, but it is inevitable if you want to support multiple inheritance and other DC features. However, in reality, multiple inheritance (some people out there consider it to be bad practice) is not needed in many cases. Or, it can be easily avoided by designing your business entities more carefully. We think that the majority of real cases are exactly those, and so we have made it possible to utilize a simpler database structure for them + other benefits that could not be used previously.

Below is the NEW way of registering the business entity I was talking about above:

  1: ...
  2: public override void Setup(XafApplication application) {
  3:     base.Setup(application);
  4:     if (!XafTypesInfo.IsInitialized) {
  5:         XafTypesInfo.Instance.RegisterEntity("Document", typeof(IDocument), typeof(BasePersistentObject));
  6:     }
  7: }
  8: ...
  9: [NonPersistent]
 10: public abstract class BasePersistentObject : BaseObject, ISupportSequentialNumber { ... }
 11: ...

Using this new mode helps me get the following database structure for my domain components definitions above:

clip_image006

If we dig more and see the auto-generated code for this entity (you can do this either by setting a breakpoint into the DevExpress.ExpressApp.DC.Xpo.TypeGenerator.GetCode method or by inspecting the generated cache DcAssembly.dll via Reflector), we will see what it looks like:

  1: ...
  2: public class Document : BasePersistentObject, IBaseDomainComponent, IDocument, ISupportSequentialNumber, ... { 
  3: ...

I intentionally omitted other XPO service stuff in the Document class declaration for the sake of simplicity. My main goal was to demonstrate that if an entity is registered AsAlias, a true class will be created behind the scenes, and this class will support all interfaces from the original domain component and its inheritance chain. Since it is a true class, an inevitable constraint comes from it - multiple inheritance is not available for “aliased” interfaces.

Before you are completely scared off and disappointed by this fact, I would provide quick clarification on it. Below, the allowed and illegal inheritance chains are demonstrated (take into account that A, B, C – are domain components registered AsAlias in your application):

A : B
B : C

or

A : B
C : B
– Both are allowed, because after generating entities there will be always a single base entity or a single inheritance chain.

A : B, C – Illegal.

Starting from 11.1, AsAlias mode is used by default, and you will receive a warning message from the deprecated AddAntityToGenerate method. You will have to either use the new RegisterEntity method and AsAlias mode or explicitly tell XAF that you want to use the old registration mode and its peculiarities.

There are still some known issues and suggestions…

Although the new AsAlias mode has greatly helped us in resolving old known issues (such as lack of server mode support, incorrect work on the Web, etc.), there are still some known issues, which we need to sort out before releasing the Domain Components technology. I separated the remaining problems into two categories, for convenience.

The first category consists of items that cause problems under certain scenarios. Those will certainly be resolved in the next minor releases, and it is sometimes even possible to workaround them in the current version. Take special note that some of these items are already NOT problems in AsAlias mode (marked in italic).

In the second category there are suggestions, based on the feedback we received from our customers. Implementing them can make the work with DC better, more convenient, but without these improvements DC can still be used normally by developers in all scenarios. Some suggestions are unique and even not present for pure persistent objects.

So, here we go:

Issues:

  • Improve support of domain components in built-in modules: System Windows Forms (support the ICategorizedItem interface), Audit Trail (make it possible to customize audit trail settings), Validation (support Rule Unique validation rule), Clone Object, Scheduler (support recurring events), etc.;
  • Support filtering by criteria, containing a key value (e.g. @CurrentUserId);
  • Support selection in the Web List Editors for unregistered base domain components* (already works in the AsAlias mode);
  • Cannot filter by the ObjectType and other XPO service fields (already works in the AsAlias mode).

Suggestions

  • Make it possible to supply a custom domain logic before deleting an object (OnDeleting);
  • Make it possible to supply a custom domain logic after an associated collection is changed (AfterListChanged);
  • Make it possible to supply a custom domain logic before a property getter or setter is executed (BeforeXXX);
  • Make it possible to mark a property as index (analog of the XPO’s IndexedAttribute);
  • Support multiple inheritance for base interfaces, containing a property with the same name;
  • Support medium trust environments.

* By unregistered base domain components we mean domain components that are parts of an entity, but are not registered as an entity. In our case, this is the IBaseDomainComponent interface.

Please note that I took only most popular customers suggestions and core issues, which are causing other side-effects or malfunctioning. So, if you are are aware of an issue that is not in this list, it is possible that it is caused by one of the core issues listed above. Feel free to verify this with Support to be sure. We will be glad to give you updates on this.

And finally, I want to announce one important thing, which I presume many of you want to hear: we hope to fix all the issues above in the next minor updates. Please stay tuned.

As always, we look forward to hearing your thoughts. Please do not hesitate to contact our Support Team if you encounter problems with certain scenarios using Domain Components or wish to propose an improvement.

Related help links:

Happy XAFingclip_image002

13 comment(s)
Liu Xinrong

Hello Dennis,

the NEW way of registering the business entity will include next version? because it is wrong in the xaf v11.1.3

XafTypesInfo.Instance.RegisterEntity("Document", typeof(IDocument), typeof(BasePersistentObject));

Thanks!

2 June, 2011
Liu Xinrong

Hello Dennis,

>>A : B

C : B – Both are allowed, because after generating entities there will be always a single base entity or a single inheritance chain.

but I test the way of registering the business entity,it occurred a error:

The 'Solution1.Module.iBaseDCC' interface must be explicitely registered as an alias because it has several derived interfaces registered as aliases.

please see the Q325452 www.devexpress.com/issue=Q325452

Can you help me?

Thanks!

2 June, 2011
Dennis (DevExpress Support)

Hello Liu,

Thank you for your feedback. We appreciate it greatly. This new feature will be included starting from version 11.1.4. It is not currently available in 11.1.3. We apologize for any possible inconvenience. I will be also glad to help you with your SC ticket. Thank you for your interest in DC!

2 June, 2011
Steven Rasmussen

With this new way are we still able to query based off of the implemented interfaces?

For example, lets say that we have the following scenario:

[DomainComponent]

public interface IAccount {}

[DomainComponent]

public interface IPerson : IAccount {}

[DomainComponent]

public interface IBusiness: IAccount {}

Then we register AsAlias both the 'IPerson' and 'IBusiness'. Are we able to get a collection of all the 'IAccount' entities?

2 June, 2011
Robert Fuchs

I hope this isn't true and I only did understand it wrong: server mode is only supported in the AsAlias mode?

2 June, 2011
Dennis (DevExpress Support)

@Steven:

In order to do this, you can register your IAccount component as alias.

3 June, 2011
Dennis (DevExpress Support)

@Robert:

Yes, the server mode is supported in both modes.

However, could you please describe your real business scenario where multiple inheritance is so important for you?

3 June, 2011
drew..

quik note: Dennis: can you get your web geeks to update this template to have the date of publication at the top, just below the title? As well, the publishers name too.. simple things like this make it more user-friendly. I want to see quickly who wrote the article and when and not have to scroll to the (sometimes very far) bottom of the page..  ;)

6 June, 2011
drew..

Hey Dennis, what about suggestions from less-popular customers?  ;) You stated: "Please note that I took only most popular customers suggestions "  ...

kidding of course, but when i first read this i thought, man, that is tough politics  ;)

6 June, 2011
Arjan van Dijk

I've the following situation

 [DomainComponent]

   [DefaultClassOptions]

   public interface ICustomer : IActive, IName, IDisplayName

   {

       string DisplayName { get; }

   }

[DomainComponent]

   public interface IName

   {

       string Name { get; set; }

   }

   [DomainComponent]

   public interface IActive

   {

       bool IsActive { get; set; }

   }

   public interface IDisplayName

   {

       [VisibleInDetailView(false)]

       string DisplayName { get; }

   }

 [DomainComponent]

   public interface IDefault

   {

       bool IsDefault { get; set; }

   }

[DomainComponent]

   [DefaultClassOptions]

   public interface IPerson : IActive, IDefault

   {

   }

this gives an error saying

"

The 'IActive' interface must be explicitely registered as an alias because it has several derived interfaces registered as aliases. "

which I don;t understand concerning your explanation above..

10 June, 2011
Klaus Liebl

Hello,

it would be nice, that someone answers  Arjan van Dijk's question.

My questions are:

1. will the "old" AddAntityToGenerate be removed in the future (without an alternative) ?

2. when loosing the possibilty of multiple interface inheritance, whats the advantage of using DCs against DOs ?

Greetings

Klaus

20 June, 2011
Dennis (DevExpress Support)

@Klaus: You can use the RegisterEntity method instead of the AddAntityToGenerate one. Its overload can still accept a boolean value as the AsAlias parameter.

29 August, 2011
Dennis (DevExpress Support)

We also elaborated more on this at www.devexpress.com/issue=Q327077

29 August, 2011

Please login or register to post comments.