Binding Fields Mapped on Related Fields

Posts   
 
    
Bruce
User
Posts: 61
Joined: 18-May-2006
# Posted on: 29-Aug-2007 22:12:39   

Using latest LLBLGenPro - updated my system last week. Using Net 1.1 for this project and SelfServicing.

I notice that fields mapped on related fields do not automatically update the control that they are bound to when the data in the entity is changed programatically or by editing another control.

I noticed this because I have a grid and on the same form I have controls that provided details of the entity selected in the grid. So the collection is bound to the grid and to these individual controls.

Some of the fields appear in both the grid and the separate controls. I discovered that with the basic entity fields when I edit in the grid and move the cursor to another column the change also occurs in the individual control (and vice versa). However, with fields mapped on related fields this does not happen. This is a Developer Express grid and I can get it to update by using MyGrid.RefreshData. I haven't found a neat way to get the outside controls to update.

In this form I also need to change CompletionDate if the User changes the StartDate. I thought I'd do this by changing the underlying entity so that the change would appear in both the Grid and the outside control. But the CompletionDate is mapped on a related field and the programmatic change does not automatically show up in the grid or the individual control.

I notice that if I change one of the normal Entity fields after I've changed a mapped field, then the mapped field change shows in the control. So it seems that changes to the mapped field are not causing a list changed event to signal the controls to update themselves.

Is this a bug or intended behaviour. Is there any way I can force a list change event to happen other than by changing another non-mapped field?

I'm using the following kind of code for each of these mapped-on-relation fields and calling it from the validated events of the grid and the individual controls to get this to work:


    Private Sub newDefectsDtFcast(ByVal newVal As Date)
        If Me.BindingContext.Item(Me.BondColl).Current.GetType Is GetType(BondEntity) Then
            Dim bondEnt As BondEntity = CType(Me.BindingContext.Item(Me.BondColl).Current, BondEntity)
            'Set the entity value (because at the time of the Validated Event 
            'of the grid the entity value has not been changed so the forced
            'list changed notification below would occur before the value changed
            'if we did not set it here)
            bondEnt.DefectsDtFcast = newVal

            'Force a list change notification by changing a non-mapped-on-relation field
            'and then changing it back - using a boolean field for convenience
            bondEnt.PccSent = Not bondEnt.PccSent
            bondEnt.PccSent = Not bondEnt.PccSent
        End If
    End Sub

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 30-Aug-2007 10:03:51   

This is a windows form, right?

Which LLBLGen Pro runtime library version are you using?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39908
Joined: 17-Aug-2003
# Posted on: 30-Aug-2007 12:08:11   

A listchange occurs if an entity IN the list changes data. The data of a related entity doesn't belong to the entity which maps a field on a related field. So if Order has a field mapped on Customer.Companyname, so Order.Companyname points to Order.Customer.Companyname, it means that if you have a list of orders, and you change an order field, it will raise EntityContentsChanged, which will result in a listchange. If you change CompanyName, it won't as it doesn't belong to the order.

It DOES raise Order.CompanyNameChanged though.

The listchanged event isn't raised because that would signal that the order entity would be changed. The thing is that that's not true, so logic which operates on the change of the entity IN the list is triggered for no reason, so it's not raised. However, databinding has a problem now, because it uses that same event.

You could add this yourself: To the derived entity class, you can add an override (in the user code region for example) to the On<FieldMappedOnRelatedFieldName>Changed method. First call the base' method, then test if the event is nothing, and if not, call: FlagMeAsChanged(). This is a method which marks the entity as 'changed' and will trigger the containing collection's Listchanged event.

You can also call FlagMeAsChanged on the entity in the list after you've set the property, that way you don't have to alter the entity. Note: this method doesnt show up in intellisense!

Frans Bouma | Lead developer LLBLGen Pro
Bruce
User
Posts: 61
Joined: 18-May-2006
# Posted on: 30-Aug-2007 12:19:12   

I'm using LLBLGenPro v2.0, VB.Net 1.1, Self Servicing, SQLServer 2000.

The dll files referenced are SD.LLBLGen.Pro.ORMSupportClasses.NET11.dll version 2.0.7.705 and SD.LLBLGen.Pro.DQE.SqlServer.NET11.dll version 2.0.7.604

Bruce
User
Posts: 61
Joined: 18-May-2006
# Posted on: 30-Aug-2007 13:31:53   

Otis.

That sounds OK. I prefer the method of adding custom code to the entity, but I don't know how to override a method within the same class.

I tried adding the following into #Region "Custom Entity Code" of my Entity, but of course I get an error saying 'OnContrStartDateChanged' has multiple definitions with identical signatures.


        Protected Overrides Sub OnContrStartDateChanged(ByVal sender As Object, ByVal e As EventArgs)
            RaiseEvent ContrStartDateChanged(Me, e)
            FlagMeAsChanged()
        End Sub

I do not understand why I need to check that the Event is not nothing. I think that the way to do this in vb is:-


           If Not ContrStartDateChangedEvent Is Nothing Then
                FlagMeAsChanged()
            End If

But it is always nothing whether I put it before or after the RaiseEvent line.

I notice that this subroutine runs for each entity when the collection is being loaded. Does FlagMeAsChanged cause the entity to be dirty and to be saved because if so then putting it in this subroutine will mean that every entity gets marked as dirty as it is loaded?

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 30-Aug-2007 15:48:18   

but I don't know how to override a method within the same class.

I think the following might be the answer. Frans' quote:

You could add this yourself: **To the derived entity **class, you can add an override (in the user code region for example)

Bruce
User
Posts: 61
Joined: 18-May-2006
# Posted on: 30-Aug-2007 16:07:45   

Walaa

I expect you might be right but your quote is not accurate. He did not embolden those words, and if I were to highlight as follows the dilemma becomes clear:

You could add this yourself: To the derived entity class, you can add an override (in the user code region for example)

I wondered to myself whether Otis might be suggesting that I derive an entity from the entity that LLBLGenPro creates. But then I'd have to spend a lot of time on the forum asking questions about how I get the related collection to use the derived entity or how should I create my own collection of these derived entities.

Then I thought, but if I derived an entity why would I bother with a **user code region **- it would all be User Code. So I thought that what he meant by derived entity must be the entity that LLBLGenpro had created because it has a User Code Region and it is of course derived from Entity Base.

So I thought he was probably in a hurry and didn't really think through what he was writing and then I spent a few hours (which I've charged to my client anyway) experimenting fruitlessly before I troubled him with another question.

Also, if it is indeed the answer in cryptic form, then it is probably only part of the answer because my post contains three questions:-

  1. How can I override the On<FieldMappedOnRelatedFieldName>Changed method?
  2. Is it really necessary to check whether the Event is nothing, and if so how can I do that in VB?
  3. Does the FlagMeAsChanged method cause the Entity to be saved when a SaveMulti is done even if it has not actually been changed?

In the meantime I've changed my code to call the FlagMeChanged method when the related fields of an entity are changed and this works. Its just not elegant.

Bruce

arschr
User
Posts: 894
Joined: 14-Dec-2003
# Posted on: 30-Aug-2007 16:37:12   

Sometimes I wish I'd stuck to writing by own DAL's!

I hope only rarely and then just for seconds before you come back to reality

Bruce
User
Posts: 61
Joined: 18-May-2006
# Posted on: 30-Aug-2007 16:40:03   

Arschr

You are right and I was in the process of editing sanity back into my peevish post as you wrote.

Bruce

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39908
Joined: 17-Aug-2003
# Posted on: 30-Aug-2007 19:10:59   

Bruce wrote:

Walaa

I expect you might be right but your quote is not accurate. He did not embolden those words, and if I were to highlight as follows the dilemma becomes clear:

You could add this yourself: To the derived entity class, you can add an override (in the user code region for example)

I wondered to myself whether Otis might be suggesting that I derive an entity from the entity that LLBLGenPro creates. But then I'd have to spend a lot of time on the forum asking questions about how I get the related collection to use the derived entity or how should I create my own collection of these derived entities.

I was assuming you were using two-classes SelfServicing simple_smile (which has a derived entity class for your code and a separate class suffixed with 'Base', which is the class with a lot of generated code).

Then I thought, but if I derived an entity why would I bother with a **user code region **- it would all be User Code. So I thought that what he meant by derived entity must be the entity that LLBLGenpro had created because it has a User Code Region and it is of course derived from Entity Base.

So I thought he was probably in a hurry and didn't really think through what he was writing and then I spent a few hours (which I've charged to my client anyway) experimenting fruitlessly before I troubled him with another question.

Also, if it is indeed the answer in cryptic form, then it is probably only part of the answer because my post contains three questions:-

  1. How can I override the On<FieldMappedOnRelatedFieldName>Changed method?

Add an override to the class. So in my Order - CompanyName example, I have in my OrderEntityBase class a method called OnCompanyNameChanged. So I create in the OrderEntity class (two class scenario for selfservicing) the override OnCompanyNameChanged and add my code there.

  1. Is it really necessary to check whether the Event is nothing, and if so how can I do that in VB?

Sorry, I was thinking in the C# mindset. If VB.NET automatically inserts code to work around this, you don't have to test. The thing is that in C#, if noone binds to an event, the eventhandler is null.

  1. Does the FlagMeAsChanged method cause the Entity to be saved when a SaveMulti is done even if it has not actually been changed?

No. All it does is raise EntityContentsChanged. This event is bound by the collection the entity is in and also by all entities which depend on this entity (so if you have order + customer and customer.FlagMeAsChanged() is called, Order will sync its FK CustomerID with customer.CustomerID. ). That's in general not something to worry about, as the fk in your situation already has that value, so nothing happens.

Frans Bouma | Lead developer LLBLGen Pro
Bruce
User
Posts: 61
Joined: 18-May-2006
# Posted on: 30-Aug-2007 22:32:51   

Otis

Thank you very much for the clear reply. I've switched to the two classes option now and added the overrides. That's great.

I had never tried the two classes option before. I just started working using the single class option when I first tried LLBGenPro about 18months ago, then copied the set up I had used on my first project for each new project and forgot that the two classes option existed.

The two classes option will be my preference from now on.

I feel that I've learnt something really useful today. Thanks again!

Bruce

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39908
Joined: 17-Aug-2003
# Posted on: 30-Aug-2007 23:31:14   

simple_smile Glad it's sorted out simple_smile

You're still on .NET 1.1 so having the extra class can be helpful. In .net 2.0, you could consider the general (1 class per entity) approach and a partial class instead.

Frans Bouma | Lead developer LLBLGen Pro