Blogs

eXpress App Framework Team

Associations in DC

     

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

This post is one in a series about our work on Domain Components (DC) framework and related component libraries. I’m just describing what we are working on, what problems we are facing and what results we've got so far.

In my previous post I was looking at INote interface:

	public interface INote {
		string Text { get; set; }
		IItemWithNotes Owner { get; set; }
	}

There is another thing I don’t like in this code: I don’t want the INote interface to know about the IItemWithNotes interface. But currently in XPO I have to define back references. Why? Let me explain the problem. Look at the class structure below:

    public class Developer : XPObject {
        private string name;
        public Developer(Session session) : base(session) { }
        public string Name {
            get { return name; }
            set { SetPropertyValue("Name", ref name, value); }
        }
        [Association]
        public XPCollection Notes { get { return GetCollection("Notes"); } }
    }
    public class Note : XPObject {
        private string text;
        public Note(Session session) : base(session) { }
        public string Text {
            get { return text; }
            set { SetPropertyValue("Text", ref text, value); }
        }
    }

These classes won't work correctly in XPO. In a relational database, a One-to-Many relation is performed by adding a foreign key to the table. For the classes above, you would create a table structure where the Note table has the foreign key column that stores a Developer's OID:

DC2-01

To retrieve the Notes that are associated with a particular Developer ID, you would write an SQL query like this: "select * from Note where Developer = <developer id>". XPO generates all queries for you. To generate the query I showed to you, XPO requires that the Note class has a property mapped to a foreign key column. In other words, the Note class should look like this:

    public class Note : XPObject {
        private string text;
        private Developer developer;

        public Note(Session session) : base(session) { }
        public string Text {
            get { return text; }
            set { SetPropertyValue("Text", ref text, value); }
        }
        [Association]
        public Developer Developer {
            get { return developer; }
            set { SetPropertyValue("Developer", ref developer, value); }
        }
    }

In this instance, XPO will find both ends of the Developer-Note association and create all necessary constraints and foreign keys.

But I’m working on the Domain Component library. My goal is to provide a framework for domain components – a puzzle's independent pieces. While writing the Note component, I don’t want it to know how anybody uses it. For instance, it can be used in the following entity (I know this is not a good design, but I still think it should be possible to do so):

    public interface IFullOfNotes {
        IList<INote> PublicNotes { get; }
        IList<INote> PrivateNotes { get; }
        IList<INote> DraftNotes { get; }
    }

To map the IFullOfNotes to the database, the Note table should have three foreign keys. If the XpoBuilder can generate back-reference (foreign key) properties automatically, our DC components will be much more flexible.

So, I want to write the following code in my Notes library:

	public interface IItemWithNotes {
		IList<INote> Notes { get; }
	}

	public interface INote {
		string Text { get; set; }
	}

I've added tests that express my desire. And again… I'm waiting for an answer from the XPO team. Stay tuned.

Published Sep 29 2008, 09:22 AM by Roman Eremin (DevExpress)
Filed under: ,
Technorati tags: XPO, DC
Bookmark and Share

Comments

 

Alexander Koger said:

Hi,

I'm still missing the link from IItemWithNotes to INote.

The internal member Notes should be declared as something like this: IList<INote> Notes.

Shouldn't it?

And would it be possible to use these DomainLogic-Attributes to build an associtation between INote and IItemWithNotes.

Then you could replace the owner by this: IList Owner.

Regards,

Alex

September 29, 2008 10:51 AM
 

Alain said:

Hi Roman

Another solution is to have a table of relationships.

Class_A_Oid --- Instance_Left_Side_Oid --- Class_B_Oid ---Instance_Right_Side_Oid --- KindOfRelationship

Regards

September 29, 2008 1:33 PM
 

Mark Krasnohorsky said:

Hi Roman,

Please make sure that there is a way to override the default association behaviour.

For example, it may be desirable to declare an IList property and populate it via the "DomainObject (marked) interface extender so, an automatic association may cause some grief. (You have a class like, product, where there is an iList called PriceList which is actually a dynamically generated set of data that is not persisted to the DB).

Thanks,

Mark

September 29, 2008 2:40 PM
 

Roman Eremin (DevExpress) said:

Alexander:

You are right, this is what was in my code. Probably <INote> pare was lost in my early code copy-paste attempt (it looks like HTML tag for the browser). I've fixed the code.

Alain:

Yes, but this will lead to indirection problems - similar to those XPO have in automatic many-to-many associations. There will be an intermediate class that should be hidden somehow.

September 29, 2008 2:49 PM
 

Mark Krasnohorsky said:

Hi Roman,

I think that it may be possible to use the association attribute at the class level:

[Association("DeveloperNotes", typeof(IItemWithNotes))

public interface IDeveloper : IPerson, IItemWithNotes{

}

or

[Association("DeveloperNotes", "Note")

public interface IDeveloper : IPerson, IItemWithNotes{

}

I think it will have to be the second one due to the fact that you can register an interface with multiple names using the "AddEntityToGenerate" method; but this means that you lose some type safety as you are using the name of the entity as it is registered via XPO.

However, this would allow for selective association.

MK

PS: I guess if the "AddEntityToGenerate" method allows for multiple registrations of the same interface, there has to be some way to specify which specific domain object class definition an interface is using.

For Example:

public interface IDeveloper : IPerson, IItemWithNotes{

}

And I have:

XafTypesInfo.Instance.AddEntityToGenerate("Developer", typeof(IDeveloper));  

XafTypesInfo.Instance.AddEntityToGenerate("Note1", typeof(INote));

XafTypesInfo.Instance.AddEntityToGenerate("Note2", typeof(INote));

How does the XPO know which INote to use for IDeveloper?

I guess the solution may be to not allow for multiple registrations of the same interface; however, I feel that something will be lost, just can't figure out what yet.

September 29, 2008 2:52 PM
 

Roman Eremin (DevExpress) said:

Hi Mark,

Yes, we will make sure that this is possible.

September 29, 2008 2:55 PM
 

Roman Eremin (DevExpress) said:

Mark:

Regarding two interfaces registered as entity - currently XpoBuilder will just throw an excption. We will deal with this problem later. We will provide a way to give system some hints how to resolve interface-entity mapping in complex cases.

September 29, 2008 4:05 PM
 

Alain said:

yes, but might be you can hide the indirection in code.

handling 1..N relationship from the base clase, to allow something like this

Relationship["Students"].Add( new Student());

In this case, we dont need to create property to each relationship in our code. Just declare the relationship in some place (might be an static method from each class)

Regards

September 29, 2008 9:01 PM
 

Tien Do said:

I just tested this XPO limitation in XAF 10.2 RC and very glad that it has been worked-around :) (and database is more complex than BO approach).

April 26, 2010 12:49 AM
More from DevExpress
Live Chat
Have a pre-sales question?
Need assistance with your evaluation?
We are here to help.
Chat is one of the many ways you can contact members of the DevExpress Team. We are available Monday-Friday between 8:30am and 5:00pm Pacific Time.
If you need additional product information, require pre-sales assistance, or want help with your order, write to us at info@devexpress.com or call us at
+1 (818) 844-3383.