How do I get the ContainingObject of an EntityCollection<TEntity> ?

Posts   
 
    
Harry
User
Posts: 73
Joined: 26-Jun-2007
# Posted on: 12-Dec-2007 14:03:35   

Is there any way to obtain the containing entity at runtime for a collection? Here is my scenario: I have a Company Entity and it has an Effective Date field. Companies have Contacts, EntityCollection<CompanyContactEntity>, these Contacts also have an Effective Date field.

I would like to have the AddNew method of the collection Company.Contact automatically set the value of the CompanyContact Entity Effective Date field equal to that of the Company that the collection belongs to.

Thanks!

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 12-Dec-2007 15:53:24   

You should handle the OnRelatedEntitySet event of either of these entities.

protected virtual void OnRelatedEntitySet( 
   IEntity relatedEntity,
   string fieldName
)

eg. implementing it in the OrderEntity class we can call.

if(fieldName == "Customer")
{
    this.OrderDate = ((CustomerEntity)relatedEntity).WhateverDate;
}
Harry
User
Posts: 73
Joined: 26-Jun-2007
# Posted on: 12-Dec-2007 16:50:19   

Thanks for the response, but I do not believe what you suggested actually fits the problem.

I can create an entity and then add it to the collection. In this instance I do not want the date to be automatically set.

In your example, how would I identify that : 1. A new item was added 2. That item as added via the AddNew method of the collection

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 12-Dec-2007 17:12:47   

Are you calling AddNew() yourself? Coz this method should only be used by databinding.

Since you won't need this behavior in all the cases, then this should not be implemented inside the entity classes, but rather in your own code, BL or UI code.

If you are doing databinding and you want to persist the added contacts with the dates copied from the Company entity, this can be done by several cases depending about your scenario. eg. in Web Apps, you can use InsertParamteres or UpdateParameters for a DataSource.

To let us suggest the best possible solution, please explain your setup in more details and please post a code snippet of what you are doing.

Harry
User
Posts: 73
Joined: 26-Jun-2007
# Posted on: 12-Dec-2007 19:23:57   

I took a closer look at the OnRelatedEntitySet method.

You should handle the OnRelatedEntitySet event of either of these entities.

Code: protected virtual void OnRelatedEntitySet( IEntity relatedEntity, string fieldName )

eg. implementing it in the OrderEntity class we can call. Code: if(fieldName == "Customer") { this.OrderDate = ((CustomerEntity)relatedEntity).WhateverDate; }

I guess what I am struggling with is that I wanted one place to write my implementation, say in a partial class extending CommonEntityBase, but this does not work as there is no way of identifying a "Containing Entity" or parent of the current entity.

Cosnider the following : Order - OrderItem -- Order

If I use the OnRelatedEntitySet method it is called 1 time for the OrderItem when it is set in the Order and then 1 more time in the Order when it is set for the OrderItem.

I can do what it is that I want but it looks like the implementation(s) will need to be specific to each individual class. rage

Unless I am missing something?

It would be nice to be able to know that the Order in the OrderItem is actually the Entity that the OrderItem is a property of.

Thanks!

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 13-Dec-2007 10:58:25   

It would be nice to be able to know that the Order in the OrderItem is actually the Entity that the OrderItem is a property of.

I didn't understand that line? What do you mean?

Doing the following:

order.OrderItems.Add(orderItem);

Will automatically set the following:

orderItem.Order = order;
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39908
Joined: 17-Aug-2003
# Posted on: 13-Dec-2007 11:25:16   

Harry wrote:

I took a closer look at the OnRelatedEntitySet method.

You should handle the OnRelatedEntitySet event of either of these entities.

Code: protected virtual void OnRelatedEntitySet( IEntity relatedEntity, string fieldName )

eg. implementing it in the OrderEntity class we can call. Code: if(fieldName == "Customer") { this.OrderDate = ((CustomerEntity)relatedEntity).WhateverDate; }

I guess what I am struggling with is that I wanted one place to write my implementation, say in a partial class extending CommonEntityBase, but this does not work as there is no way of identifying a "Containing Entity" or parent of the current entity.

Cosnider the following : Order - OrderItem -- Order

If I use the OnRelatedEntitySet method it is called 1 time for the OrderItem when it is set in the Order and then 1 more time in the Order when it is set for the OrderItem.

I can do what it is that I want but it looks like the implementation(s) will need to be specific to each individual class. rage

Unless I am missing something?

It would be nice to be able to know that the Order in the OrderItem is actually the Entity that the OrderItem is a property of.

Thanks!

You want this feature for CompanyEntity, so you have to override it in a partial class of CompanyEntity. There you cast relatedEntity to CompanyContactEntity using 'as' to see if it's indeed that type, and if so, set its EffectiveDate field to the Company entity's value.

You can also use fieldName to identify the entity. This is the field mapped onto the relation. So in Customer - Order, it's 'Orders' in the CustomerEntity and 'Customer' in the order entity.

Or is 'effective date' a field which is present in all entities?

Frans Bouma | Lead developer LLBLGen Pro
Harry
User
Posts: 73
Joined: 26-Jun-2007
# Posted on: 13-Dec-2007 18:19:38   

You want this feature for CompanyEntity, so you have to override it in a partial class of CompanyEntity. There you cast relatedEntity to CompanyContactEntity using 'as' to see if it's indeed that type, and if so, set its EffectiveDate field to the Company entity's value.

You can also use fieldName to identify the entity. This is the field mapped onto the relation. So in Customer - Order, it's 'Orders' in the CustomerEntity and 'Customer' in the order entity.

Or is 'effective date' a field which is present in all entities?

In the current system Effective Date and a few other fields will actually exist in about 80% of the tables/entities.

The basic relationship I would like to be able to express is : Order **has **OrderItems. OrderItem **belongs to **Order.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39908
Joined: 17-Aug-2003
# Posted on: 13-Dec-2007 18:35:08   

Harry wrote:

You want this feature for CompanyEntity, so you have to override it in a partial class of CompanyEntity. There you cast relatedEntity to CompanyContactEntity using 'as' to see if it's indeed that type, and if so, set its EffectiveDate field to the Company entity's value.

You can also use fieldName to identify the entity. This is the field mapped onto the relation. So in Customer - Order, it's 'Orders' in the CustomerEntity and 'Customer' in the order entity.

Or is 'effective date' a field which is present in all entities?

In the current system Effective Date and a few other fields will actually exist in about 80% of the tables/entities.

The basic relationship I would like to be able to express is : Order **has **OrderItems. OrderItem **belongs to **Order.

WHat has that remark about orders to do with effective date? OrderItem is an entity, EffectiveDate is a value.

LLBLGen Pro doesn't support value types (yet) as in DDD value types. So OrderItem is related to Order and Order is related to OrderItem, they don't belong together, they're related.

Nevertheless, you could solve this differently: you could define an interface to which you cast in the OnRelatedEntitySet method. the interface has EffectiveDate get/set. if the entity doesn't implement the interface, using 'as', will result in null, otherwise you can set the property in common code in the commonbase class.

You can generate the usage of the interface by specifying it in the entity editor (or using the plugin to set it in bulk). As the entity already has a get/set for the EffectiveDate, you have no other code to add. Just define the interface somewhere in scope in the project.

Frans Bouma | Lead developer LLBLGen Pro
Harry
User
Posts: 73
Joined: 26-Jun-2007
# Posted on: 13-Dec-2007 19:01:06   

Nevertheless, you could solve this differently: you could define an interface to which you cast in the OnRelatedEntitySet method. the interface has EffectiveDate get/set. if the entity doesn't implement the interface, using 'as', will result in null, otherwise you can set the property in common code in the commonbase class.

I agree, and that is how I am doing it.

Order and OrderItem both have the property Effective Date.

I was simply trying to avoid having to implement the functionality per class.

I think my answer may live somewhere in the relations and looking at the PK vs FK....

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 14-Dec-2007 10:14:10   

IMHO your database contain redundant information if both dates will always be equal, then you just need the one in the Order table not the ones in the OrderItem. Since OrderItem refer to Order anyway.

Harry
User
Posts: 73
Joined: 26-Jun-2007
# Posted on: 14-Dec-2007 14:04:58   

I agree, as such Order and OrderItem are poor choices for the example.

Lets use the other Company based example.

In my system there is a Company and that Company will have many contacts.

So in our database we have: Company - CompanyID, Name, Effective Date, End Date Contact - ContactID, First Name, Last Name, DOB, etc... CompanyContact - CompanyContactID, CompanyID, ContactID, Effective Date, End Date

The above generates the object model: IEffectiveDate - Effective Date

Company : IEffectiveDate - CompanyID - Name - Effective Date - End Date - CompanyContact (1:n)

CompanyContact : IEffectiveDate - CompanyContactID - CompanyID - Company (m:1) - ContactID - Contact (m:1) - Effective Date - End Date

Contact - ContactID - CompanyContact (1:n) - CompanyCollectionViaCompanyContact (m:n) - First Name - Last Name - DOB

So far so good? So at runtime we create our Company and begin to add CompanyContacts to our collection. The collection has a property that designates, for lack of a better term, a parent. The containingEntity property of the collection allows you to say "CompanyContacts [b]belongs to[/b] Company".

IMHO, we should be able to do the same with Entity objects as well. When we add a CompanyContact to the collection there should be some way to mark the CompanyContact to indicate it also belongs to the Company. I believe this would be helpful in routines, like the OnRelatedEntitySet, where you have the ability to overflow the stack because of endless loops produced.

The above model, and the code below would cause an endless loop:

public partial class CommonEntityBase { protected override void OnRelatedEntitySet(IEntity2 relatedEntity, string fieldName) { base.OnRelatedEntitySet(relatedEntity, fieldName); IEffectiveDate currentEntity = this as IEffectiveDate; if (currentEntity != null) { // We only want the values set 1 time as a "Default" if (this.IsNew && !Fields["EffectiveDate"].IsChanged) { IEffectiveDate entity = relatedEntity as IEffectiveDate; if (entity != null) { currentEntity.EffectiveDate = entity.EffectiveDate; } } } } }

We could easily fix the endless loop if we could say : if(currentEntity != null && this.ContainingObject != relatedEntity)

What do you think?

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 14-Dec-2007 16:23:35   

The above model, and the code below would cause an endless loop:

public partial class CommonEntityBase { protected override void OnRelatedEntitySet(IEntity2 relatedEntity, string fieldName) { base.OnRelatedEntitySet(relatedEntity, fieldName); IEffectiveDate currentEntity = this as IEffectiveDate; if (currentEntity != null) { // We only want the values set 1 time as a "Default" if (this.IsNew && !Fields["EffectiveDate"].IsChanged) { IEffectiveDate entity = relatedEntity as IEffectiveDate; if (entity != null) { currentEntity.EffectiveDate = entity.EffectiveDate; } } } } }

I might be missing something here but I failed to understand why the above method will go in endless loop, there is no recursion in it, is there? In this method, you are only setting field values, right?

Harry
User
Posts: 73
Joined: 26-Jun-2007
# Posted on: 09-Jan-2008 20:55:30   

Sorry for soo long to get back on this. You are correct and I was confusing this issue with a different issue. We have this figured out. Thanks for all the help!