Setting a subobject : works one time, doesn't another

Posts   
1  /  2
 
    
HcD avatar
HcD
User
Posts: 214
Joined: 12-May-2005
# Posted on: 07-Oct-2005 00:47:41   

Hi,

I have the following problem.

I have an entity "ContractZaaiDatumEntity" with several subobjects( FK to another entity) In the code I set the subobjects as following:


  ContractZaaidatumArticleEntity cza;
  //initialize cza
  ArticleEntity a  = new ArticleEntity(selected_code);
  cza.Article = a;//this makes that cza.ArId = a.ArId = selected_code)

This works like a charm. The foreign key on cza is updated as it should be.

Now i also have another subobject PerceelEntity. This one behaves very strange


  ContractZaaidatumArticleEntity cza;
  //initialize cza
  PerceelEntity p  = new PerceelEntity(selected_code);
  cza.Perceel = p;//this SHOULD make that cza.PlId = p.PlId = selected_code

This is where it goes wrong. I can debug upto the last line, and inspect to see that the PerceelEntity is correct. The last line then gives me the error:


Object reference not set to an instance of an object
System.NullReferenceException
   at SD.LLBLGen.Pro.ORMSupportClasses.EntityBase.UnsetEntitySyncInformation(String fieldName, IEntity relatedEntity, IEntityRelation relation)
   at Agro.Datalayer.EntityClasses.ContractZaaidatumArticleEntityBase.DesetupSyncPerceel(Boolean signalRelatedEntity) in D:\projects\Agro\Agro.Datalayer\EntityBaseClasses\ContractZaaidatumArticleEntityBase.cs:line 1293
   at Agro.Datalayer.EntityClasses.ContractZaaidatumArticleEntityBase.SetupSyncPerceel(IEntity relatedEntity) in D:\projects\Agro\Agro.Datalayer\EntityBaseClasses\ContractZaaidatumArticleEntityBase.cs:line 1308
   at Agro.Datalayer.EntityClasses.ContractZaaidatumArticleEntityBase.SetRelatedEntity(IEntity relatedEntity, String fieldName) in D:\projects\Agro\Agro.Datalayer\EntityBaseClasses\ContractZaaidatumArticleEntityBase.cs:line 407
   at SD.LLBLGen.Pro.ORMSupportClasses.EntityCollectionBase.FastAdd(IEntity entityToAdd)
   at SD.LLBLGen.Pro.ORMSupportClasses.EntityCollectionBase.Add(IEntity entityToAdd)
   at Agro.Datalayer.EntityClasses.PerceelEntityBase.SetRelatedEntity(IEntity relatedEntity, String fieldName) in D:\projects\Agro\Agro.Datalayer\EntityBaseClasses\PerceelEntityBase.cs:line 745
   at Agro.Datalayer.EntityClasses.ContractZaaidatumArticleEntityBase.set_Perceel(PerceelEntity value) in D:\projects\Agro\Agro.Datalayer\EntityBaseClasses\ContractZaaidatumArticleEntityBase.cs:line 1987
   at Agro.Forms.ZaaiDatumsControl.btnZoekVerkoopsArtikelPerceel_Click(Object sender, EventArgs e) in d:\projects\agro\agro.forms\zaaidatumscontrol.cs:line 648

what is going on here ? I have used this mechanism of setting subobject maybe hundreds of times throughout our rather large project with lots and lots of differenct objects and subobjects (believe me we have plenty), and i nowhere encountered this behaviour.

Ofcourse i then tried the next obvious step, directly setting the foreign key value eg.:


  ContractZaaidatumArticleEntity cza;
  //initialize cza
  PerceelEntity p  = new PerceelEntity(selected_code);//such a subobject
  cza.PlId = selected_code

This code does not crash as above, but does .. nothing rage When debugging this, the cza.PlId is 0 before the last line, and when stepping over it, it is still 0 ! (although selected_code is not 0) When stepping into the code i stumpbled upon the line


            if(SetNewFieldValue((int)ContractZaaidatumArticleFieldIndex.PlId, value))
                {
                    OnPlIdChanged();
                }

I cannot step into this further, but OnPlIdChanged() gets called, although ContractZaaidatumArticleFieldIndex.PlId still is 0 !?!? (and value was 14 in this particular debug session )

I'm giving up, anybody got a clue ??

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39933
Joined: 17-Aug-2003
# Posted on: 07-Oct-2005 09:44:26   

Check if the relation Perceel - ContractZaaiDatum is there and not hidden. Selfservicing doesn't support single-side hidden / created relations, relations have to be either hidden on both sides or visible on both sides.

It's a strange error indeed. I haven't seen this one before. So stating the obvious: check if you're using the latest templates and the latest runtimes, and also check if the code you're using is up to date as in: recently generated.

Frans Bouma | Lead developer LLBLGen Pro
HcD avatar
HcD
User
Posts: 214
Joined: 12-May-2005
# Posted on: 07-Oct-2005 12:14:47   

Ok, I will try this tonight. Incidentally I have to regenerate the datalayer due to some minor database changes anyway. I'm still using the LLBL version of somewhere in may, I think may 10th. I had no problems with it so far, and due to the size of the project I wasn't attracted to upgrade to a newer version. Also I will check if the relation is hidden, although I would be very surprised if it were. I didn't change the hidden setting on any relelation afaik frowning

HcD avatar
HcD
User
Posts: 214
Joined: 12-May-2005
# Posted on: 07-Oct-2005 16:47:38   

Hmm this gets weirder and weirder. Consider the following code


    ContractZaaidatumArticleEntity obj = new ContractZaaidatumArticleEntity();
    obj.ContractZaaidatum = m_currentContractZaaidatum;
    obj.PlId = 14;

    ContractZaaidatumArticleEntity obj2 = new ContractZaaidatumArticleEntity();
    obj2.ContractZaaidatum = m_currentContractZaaidatum;
    obj2.PlId = 14;
                
    int i = obj.PlId ;
    int i2 = obj2.PlId ;

After execution i = 0 but i2 = 14 (?!) . If I replace the code with


    PerceelEntity p = new PerceelEntity(14);

    ContractZaaidatumArticleEntity obj = new ContractZaaidatumArticleEntity();
    obj.ContractZaaidatum = m_currentContractZaaidatum;
*crash* obj.Perceel = p;

    ContractZaaidatumArticleEntity obj2 = new ContractZaaidatumArticleEntity();
    obj2.ContractZaaidatum = m_currentContractZaaidatum;
    obj2.Perceel = p;
    
    int i = obj.PlId ;
    int i2 = obj2.PlId ;

It crashes on the indicated line with the errormessage as seen in my openingpost.

Now the next


    PerceelEntity p = new PerceelEntity(14);

    ContractZaaidatumArticleEntity obj = new ContractZaaidatumArticleEntity();
    //obj.ContractZaaidatum = m_currentContractZaaidatum;
    obj.Perceel = p;

    ContractZaaidatumArticleEntity obj2 = new ContractZaaidatumArticleEntity();
    //obj2.ContractZaaidatum = m_currentContractZaaidatum;
    obj2.Perceel = p;
    
    int i = obj.PlId ;
    int i2 = obj2.PlId ;


works as expected, both i =14 and i2 = 14. and finally


    PerceelEntity p = new PerceelEntity(14);

    ContractZaaidatumArticleEntity obj = new ContractZaaidatumArticleEntity();
    //obj.ContractZaaidatum = m_currentContractZaaidatum;
    obj.Perceel = p;

    ContractZaaidatumArticleEntity obj2 = new ContractZaaidatumArticleEntity();
    obj2.ContractZaaidatum = m_currentContractZaaidatum;
*crash* obj2.Perceel = p;
    
    int i = obj.PlId ;
    int i2 = obj2.PlId ;


crashes on the indicated line with the above errormessage.

Does this makes ANY sense ?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39933
Joined: 17-Aug-2003
# Posted on: 08-Oct-2005 13:41:35   

HcD wrote:

Hmm this gets weirder and weirder. Consider the following code


    ContractZaaidatumArticleEntity obj = new ContractZaaidatumArticleEntity();
    obj.ContractZaaidatum = m_currentContractZaaidatum;
    obj.PlId = 14;

    ContractZaaidatumArticleEntity obj2 = new ContractZaaidatumArticleEntity();
    obj2.ContractZaaidatum = m_currentContractZaaidatum;
    obj2.PlId = 14;
                
    int i = obj.PlId ;
    int i2 = obj2.PlId ;

After execution i = 0 but i2 = 14 (?!) .

This is a weird thing indeed, I have no explanation for this, as the code for both is identical and you don't tie the objects together in any way..

If I replace the code with


    PerceelEntity p = new PerceelEntity(14);

    ContractZaaidatumArticleEntity obj = new ContractZaaidatumArticleEntity();
    obj.ContractZaaidatum = m_currentContractZaaidatum;
*crash* obj.Perceel = p;

    ContractZaaidatumArticleEntity obj2 = new ContractZaaidatumArticleEntity();
    obj2.ContractZaaidatum = m_currentContractZaaidatum;
    obj2.Perceel = p;
    
    int i = obj.PlId ;
    int i2 = obj2.PlId ;

It crashes on the indicated line with the errormessage as seen in my openingpost.

Which is totally weird. I have a lot of unittests which do the same thing, and work. disappointed

Now the next


    PerceelEntity p = new PerceelEntity(14);

    ContractZaaidatumArticleEntity obj = new ContractZaaidatumArticleEntity();
    //obj.ContractZaaidatum = m_currentContractZaaidatum;
    obj.Perceel = p;

    ContractZaaidatumArticleEntity obj2 = new ContractZaaidatumArticleEntity();
    //obj2.ContractZaaidatum = m_currentContractZaaidatum;
    obj2.Perceel = p;
    
    int i = obj.PlId ;
    int i2 = obj2.PlId ;

works as expected, both i =14 and i2 = 14.

frowning ... I have no idea why contractzaaidatum would be of any influence on Perceel (in the model that is wink ) p is not new, so when you do obj.Perceel = p; it will sync the PK of p with the FK in obj, which is PlId...

However... checking your initial post, and stack trace, I see it calls DesetupSyncPerceel and from that UnsetEntitySyncInformation. This is strange as the templates clearly generate a method for DesetupSyncPerceel which should look like:


private void DesetupSyncPerceel(bool signalRelatedEntity)
{
    if(_perceel != null)
    {
//... 
        // disconnect the entity from this entity
        _perceel .AfterSave-=new EventHandler(OnEntityAfterSave);
        if(signalRelatedEntity)
        {
            _perceel .UnsetRelatedEntity(this, "ContractZaaiDatumArticle");
        }
        base.UnsetEntitySyncInformation("Perceel", _perceel , //... 
        
        SetNewFieldValue((int)ContractZaaiDatumArticleFieldIndex.PlId, null, false);
        _perceel = null;
    }
}

So in other words, if _perceel is null (which is IMHO the case in your code, as it is NOT related to any object when you call it at that line), it should never end up in UnsetEntitySyncInformation. Could you set a break point in DesetupSyncPerceel and also check if your code is generated with recent templates please?

and finally


    PerceelEntity p = new PerceelEntity(14);

    ContractZaaidatumArticleEntity obj = new ContractZaaidatumArticleEntity();
    //obj.ContractZaaidatum = m_currentContractZaaidatum;
    obj.Perceel = p;

    ContractZaaidatumArticleEntity obj2 = new ContractZaaidatumArticleEntity();
    obj2.ContractZaaidatum = m_currentContractZaaidatum;
*crash* obj2.Perceel = p;
    
    int i = obj.PlId ;
    int i2 = obj2.PlId ;


crashes on the indicated line with the above errormessage.

Does this makes ANY sense ?

It actually doesn't, indeed... So I'd like to ask you to examine your generated code and also if you do any initialisation yourself which might cause havoc later on.

Frans Bouma | Lead developer LLBLGen Pro
HcD avatar
HcD
User
Posts: 214
Joined: 12-May-2005
# Posted on: 08-Oct-2005 18:30:01   

Ok, i still haven't re-generated yet, had no time yesterday. I will first try to debug in the Desync routine with the current code. With recent templates you mean downloading the latest LLBLGen generator right ? (i'm still using the version from may) .Will my regenerated datalyer be fully compatible with the current version ? Because there is allready an application running at the customer site with the current datalayer, and also my current .lgp-project file contains a lot of custom named relations, don't wanna lose those smile

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39933
Joined: 17-Aug-2003
# Posted on: 08-Oct-2005 20:25:01   

HcD wrote:

Ok, i still haven't re-generated yet, had no time yesterday. I will first try to debug in the Desync routine with the current code. With recent templates you mean downloading the latest LLBLGen generator right ? (i'm still using the version from may) .Will my regenerated datalyer be fully compatible with the current version ? Because there is allready an application running at the customer site with the current datalayer, and also my current .lgp-project file contains a lot of custom named relations, don't wanna lose those smile

There shouldn't be a problem, the API is compatible. As always: test first, then deploy, just for safety wink . (to be sure you didn't program using the behavior of a bug, which makes your program not function correctly if the bug is fixed)

Frans Bouma | Lead developer LLBLGen Pro
HcD avatar
HcD
User
Posts: 214
Joined: 12-May-2005
# Posted on: 09-Oct-2005 00:52:59   

I regenerated with the latest templates (Templates_08122005.zip) and also needed the latest runtimes (RuntimeLibraries_10082005.zip) Then with "volle moed" a new test


1:  PerceelEntity p = new PerceelEntity(14);

2:  ContractZaaidatumArticleEntity obj = new ContractZaaidatumArticleEntity();
3:  obj.ContractZaaidatum = m_currentContractZaaidatum;
4:  obj.Perceel = p;

Crash on line 4. So i have opened ContractZaaidatumArticleEntityBase.cs and looked up the DesetupSyncPerceel function and set a breakpoint on the first line. Imagine my surprise that the breakpoint was hit during the execution of line 3, i expected during line 4. So i looked in the callstack and saw it was because of a "custom property" in the ContractZaaidatumArticleentity.cs class.


// __LLBLGENPRO_USER_CODE_REGION_START CustomEntityCode
    public string PerceelName
    {
        get
        {
            return this.Perceel.PlName;
        }
    }
// __LLBLGENPRO_USER_CODE_REGION_END

If often use "shortcuts" like this, because it allows me to display subobject-childproperties into a grid. Anyway, to prevent entering the DesetupSyncPerceel at this time, i changed to property to :


// __LLBLGENPRO_USER_CODE_REGION_START CustomEntityCode
    public string PerceelName
    {
        get
        {
            if (this.PlId == 0)
                return "";
            return this.Perceel.PlName;
        }
    }
// __LLBLGENPRO_USER_CODE_REGION_END

And indeed, execution of line 3 does not hit my breakpoint now. But line 4 does ..and again, and again, and again , an endless loop...each time with "signalRelatedEntity" toggling between false and true, .. and when i disable the breakpoint and run, my dialog just closes itself and it's parent dialogs and terminates back to the IDE, no error message at all. I would expect a stack overflow due to the endless loop. If i replace the property with


// __LLBLGENPRO_USER_CODE_REGION_START CustomEntityCode
    public string PerceelName
    {
        get
        {
            return "";
        }
    }
// __LLBLGENPRO_USER_CODE_REGION_END

i get no crash at all. But offcourse i also don't see the PerceelName in my bound control. there you have it, databinding ! I must have something to do with that, if i replace the databinding with manual handling i have no crash. But how is this possible ? i have used this mechanism with "custom properties" on hundreds of occasions all troughout the project, and all with databinding. I even have the exact same custom property on my ContractZaaidatumPerceelEntity, where the PerceelName is also databound. So to convince myself, i make a similar testcase with ContractZaaidatumPerceelEntity and boom : a StackOverFlowException. I'm SURE it worked before, so i do an "Undo Checkout All" on my datalayer, recompile and it works !! (with the old runtimes again)

/me is going nuts ...

HcD avatar
HcD
User
Posts: 214
Joined: 12-May-2005
# Posted on: 10-Oct-2005 00:00:12   

I don't know if this is related to it, but i also had some other "strange behaviors" with the new templates. Eg the following code


    SeasonSupplierEntity seasup = new SeasonSupplierEntity();
    seasup.Season = m_currentEntity;
    seasup.SupId = code;
    SetBindings();

now also results in an StackOverFlowException. And it worked before ! I changed the code to


    SeasonSupplierEntity seasup = new SeasonSupplierEntity();
    seasup.Season = m_currentEntity;
    seasup.Supplier = new SupplierEntity(code);
    SetBindings();

and fortunately then it works. But why is this ?

HcD avatar
HcD
User
Posts: 214
Joined: 12-May-2005
# Posted on: 10-Oct-2005 01:20:40   

Hi,

i could regenerate my stack overflow. I think it must be somehow connected to my problem in the openingpost, because it is also in the setupsync - desetupsync routines that it crashes. Here's how to regenerate the stack overflow "in 5 easy steps" wink

STEP1: In SQL server create 3 simple tables in a new database - a Season table, with primary key SeaID , and a SeaName textfield - a Supplier table with primary key SupID , and a SupName textfield - a SeasonSupplier table with foreign keys SeaId and SupId, and an seasupName textfield Set the foreing key constraints in the "manage relations" dialog for SeasonSupplier STEP2: Generate the datalayer in LLBL 1.0.2004.2 using "Templates_08122005.zip" in SelfServicing Full/Safe for VS2003 STEP3: In SeasonSupplierEntity add the following code


        // __LLBLGENPRO_USER_CODE_REGION_START CustomEntityCode
        public string SupplierName
        {
            get
            {
                if (this.Supplier == null)
                    return "";
                return this.Supplier.SupName;
            }
        }
        // __LLBLGENPRO_USER_CODE_REGION_END

and compile the datalyer STEP4: Make a new Windows Application project, and reference the datalayer, add a app.config, set the correct Main.ConnectionString key. In the form, add a button and a listbox On the buttonclick handler, add the code


        private void button1_Click(object sender, System.EventArgs e)
        {
            SeasonEntity sea = new SeasonEntity();  
            SeasonSupplierEntity seasup = new SeasonSupplierEntity();
            seasup.Season = sea;
            seasup.SupId = 1;
            listBox1.DataSource =  sea.SeasonSupplier;
            listBox1.DisplayMember = "SupplierName";
        }

STEP5: Run the program and click button1 boom "An unhandled exception of type 'System.StackOverflowException' occurred in bugtest.dll"


>   bugtest.dll!Bugtest.EntityClasses.SeasonSupplierEntityBase.DesetupSyncSupplier(bool signalRelatedEntity = true) Line 922 + 0x21 bytes   C#
    bugtest.dll!Bugtest.EntityClasses.SeasonSupplierEntityBase.SetupSyncSupplier(SD.LLBLGen.Pro.ORMSupportClasses.IEntity relatedEntity = {Bugtest.EntityClasses.SupplierEntity}) Line 956  C#
    bugtest.dll!Bugtest.EntityClasses.SeasonSupplierEntityBase.SetRelatedEntity(SD.LLBLGen.Pro.ORMSupportClasses.IEntity relatedEntity = {Bugtest.EntityClasses.SupplierEntity}, string fieldName = "Supplier") Line 346    C#
    [<Non-user Code>]   
    bugtest.dll!Bugtest.EntityClasses.SupplierEntityBase.SetRelatedEntity(SD.LLBLGen.Pro.ORMSupportClasses.IEntity relatedEntity = {Bugtest.EntityClasses.SeasonSupplierEntity}, string fieldName = "SeasonSupplier") Line 331 + 0xf bytes  C#
    bugtest.dll!Bugtest.EntityClasses.SeasonSupplierEntityBase.set_Supplier(Bugtest.EntityClasses.SupplierEntity value = {Bugtest.EntityClasses.SupplierEntity}) Line 1307  C#
    bugtest.dll!Bugtest.EntityClasses.SeasonSupplierEntityBase.GetSingleSupplier(bool forceFetch = false) Line 594  C#
    bugtest.dll!Bugtest.EntityClasses.SeasonSupplierEntityBase.get_Supplier() Line 1275 + 0xc bytes C#
    bugtest.dll!Bugtest.EntityClasses.SeasonSupplierEntity.get_SupplierName() Line 129 + 0xa bytes  C#
    [<Non-user Code>]   

Oh, and replacing the code with


        private void button1_Click(object sender, System.EventArgs e)
        {
            SeasonEntity sea = new SeasonEntity();  
            SeasonSupplierEntity seasup = new SeasonSupplierEntity();
            seasup.Season = sea;
            seasup.Supplier = new SupplierEntity();
            listBox1.DataSource =  sea.SeasonSupplier;
            listBox1.DisplayMember = "SupplierName";
        }

does NOT result in an error.

I feel somehow it must be connected to my original problem ...

off to bed now, have been spending WAY too much time on this one rage

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39933
Joined: 17-Aug-2003
# Posted on: 10-Oct-2005 10:22:51   

Thanks for the steps, I'll look into it.

One note:


           {
                if (this.Supplier == null)
                    return ""; // A
                return this.Supplier.SupName;
            }

Line A will never be hit, as this.Supplier will fetch the Supplier from the db, and return a new one if it's not there, so it's never null.

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39933
Joined: 17-Aug-2003
# Posted on: 10-Oct-2005 11:37:45   

HcD wrote:

Hi,

i could regenerate my stack overflow. I think it must be somehow connected to my problem in the openingpost, because it is also in the setupsync - desetupsync routines that it crashes. Here's how to regenerate the stack overflow "in 5 easy steps" wink

STEP1: In SQL server create 3 simple tables in a new database - a Season table, with primary key SeaID , and a SeaName textfield - a Supplier table with primary key SupID , and a SupName textfield - a SeasonSupplier table with foreign keys SeaId and SupId, and an seasupName textfield Set the foreing key constraints in the "manage relations" dialog for SeasonSupplier STEP2: Generate the datalayer in LLBL 1.0.2004.2 using "Templates_08122005.zip" in SelfServicing Full/Safe for VS2003 STEP3: In SeasonSupplierEntity add the following code


        // __LLBLGENPRO_USER_CODE_REGION_START CustomEntityCode
        public string SupplierName
        {
            get
            {
                if (this.Supplier == null)
                    return "";
                return this.Supplier.SupName;
            }
        }
        // __LLBLGENPRO_USER_CODE_REGION_END

and compile the datalyer STEP4: Make a new Windows Application project, and reference the datalayer, add a app.config, set the correct Main.ConnectionString key. In the form, add a button and a listbox On the buttonclick handler, add the code


        private void button1_Click(object sender, System.EventArgs e)
        {
            SeasonEntity sea = new SeasonEntity();  
            SeasonSupplierEntity seasup = new SeasonSupplierEntity();
            seasup.Season = sea;
            seasup.SupId = 1;
            listBox1.DataSource =  sea.SeasonSupplier;
            listBox1.DisplayMember = "SupplierName";
        }

STEP5: Run the program and click button1 boom "An unhandled exception of type 'System.StackOverflowException' occurred in bugtest.dll"

It worked, when my db was empty.

When I manually added a supplier with id 1, I got the exception. Will look into it.

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39933
Joined: 17-Aug-2003
# Posted on: 10-Oct-2005 11:55:40   

Ok, here's the deal.

Your property does this:


public string SupplierName
{
    get
    {
        if (this.Supplier == null)           // A
            return "";
        return this.Supplier.SupName;
    }
}

At line A, it will perform a fetch. During this fetch it will setup sync information. And because Supplier isn't new, it will synchronize its PK with the FK fields in SeasonSupplier.

So, what happens then is that it flags itself as changed, an event is fired, and because the listbox is bound to the collection of SeasonSuppliers, and receives an event the collection is changed. It then starts re-reading the properties of the entities to update itself.

.. it ends up in the property SupplierName again, and again at line A. It steps into this.Supplier again and re-starts fetching the data. It does this because the flag to stop lazy loading is set AFTER the syncing of the PK-FK has been completed. But it never arrives there before restarting the complete cycle.

Possible fix is to set the lazy loading flag earlier in the routine. I'll look into a proper fix for this.

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39933
Joined: 17-Aug-2003
# Posted on: 10-Oct-2005 12:07:57   

Fixed in next build.

Frans Bouma | Lead developer LLBLGen Pro
HcD avatar
HcD
User
Posts: 214
Joined: 12-May-2005
# Posted on: 10-Oct-2005 15:05:05   

Sweet , thank you simple_smile

What is strange though is that with the previous version of the templates, this was never an issue. Now i have popping up these stack overflows all over the place (i use databinding and custom properties quite extensively). I just hope my opening post is also fixed with this. For the time being i fixed my original problem as follows :


PerceelEntity p = new PerceelEntity(selected_code);
cza.Perceel = p; //<- this one crashes
Setbindings();

workaround by:


PerceelEntity p = new PerceelEntity(selected_code);
m_currentContractZaaidatum.ContractZaaidatumArticle.Remove(cza);
cza.Perceel = p;
m_currentContractZaaidatum.ContractZaaidatumArticle.Add(cza);
SetBindings();

when the new build (=new runtime ?) arrives i'll let you know !!

Thanks for the EXCELLENT support once again !

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39933
Joined: 17-Aug-2003
# Posted on: 10-Oct-2005 15:26:35   

HcD wrote:

Sweet , thank you simple_smile

What is strange though is that with the previous version of the templates, this was never an issue. Now i have popping up these stack overflows all over the place (i use databinding and custom properties quite extensively).

There was an issue in the runtime libs which didn't signal a change event when an FK field was synced. This was changed in late May together with a template change.

I just hope my opening post is also fixed with this.

yes it's related.

when the new build (=new runtime ?) arrives i'll let you know !!

I'll push out an archive later today so you can test it then immediately. If you need it now, let me know and I'll mail it to you simple_smile

Thanks for the EXCELLENT support once again !

simple_smile And sorry for the inconvenience wink

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39933
Joined: 17-Aug-2003
# Posted on: 10-Oct-2005 18:48:54   

Fix is now available (new template package).

Frans Bouma | Lead developer LLBLGen Pro
HcD avatar
HcD
User
Posts: 214
Joined: 12-May-2005
# Posted on: 10-Oct-2005 21:37:27   

Ok,

well the good news is that all the stackoverflows that showed up when moving to the 08/10/2005 templates are now fixed with the 10/10/2005 templatessimple_smile The bad news is that my error from the openingpost is still happening...

i will try to make an isolated testcase as soon as possible, but basically this is happening :


    ContractZaaidatumArticleEntity cza = new ContractZaaidatumArticleEntity();
    m_currentContractZaaidatum.ContractZaaidatumArticle.Add(cza);
    cza.Perceel = new PerceelEntity(14);

results in


Object reference not set to an instance of an object
System.NullReferenceException
   at SD.LLBLGen.Pro.ORMSupportClasses.EntityBase.UnsetEntitySyncInformation(String fieldName, IEntity relatedEntity, IEntityRelation relation)
   at Agro.Datalayer.EntityClasses.ContractZaaidatumArticleEntityBase.DesetupSyncPerceel(Boolean signalRelatedEntity) in D:\projects\Agro\Agro.Datalayer\EntityBaseClasses\ContractZaaidatumArticleEntityBase.cs:line 1331
   at Agro.Datalayer.EntityClasses.ContractZaaidatumArticleEntityBase.SetupSyncPerceel(IEntity relatedEntity) in D:\projects\Agro\Agro.Datalayer\EntityBaseClasses\ContractZaaidatumArticleEntityBase.cs:line 1358
   at Agro.Datalayer.EntityClasses.ContractZaaidatumArticleEntityBase.SetRelatedEntity(IEntity relatedEntity, String fieldName) in D:\projects\Agro\Agro.Datalayer\EntityBaseClasses\ContractZaaidatumArticleEntityBase.cs:line 407
   at SD.LLBLGen.Pro.ORMSupportClasses.EntityCollectionBase.FastAdd(IEntity entityToAdd)
   at SD.LLBLGen.Pro.ORMSupportClasses.EntityCollectionBase.Add(IEntity entityToAdd)
   at Agro.Datalayer.EntityClasses.PerceelEntityBase.SetRelatedEntity(IEntity relatedEntity, String fieldName) in D:\projects\Agro\Agro.Datalayer\EntityBaseClasses\PerceelEntityBase.cs:line 745
   at Agro.Datalayer.EntityClasses.ContractZaaidatumArticleEntityBase.set_Perceel(PerceelEntity value) in D:\projects\Agro\Agro.Datalayer\EntityBaseClasses\ContractZaaidatumArticleEntityBase.cs:line 2056
   at Agro.Forms.ZaaiDatumsControl.btnToevoegenVerkoopsartikel_Click(Object sender, EventArgs e) in d:\projects\agro\agro.forms\zaaidatumscontrol.cs:line 704
   at System.Windows.Forms.Control.OnClick(EventArgs e)
   at System.Windows.Forms.Button.OnClick(EventArgs e)
   at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
   at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.ButtonBase.WndProc(Message& m)
   at System.Windows.Forms.Button.WndProc(Message& m)
   at System.Windows.Forms.ControlNativeWindow.OnMessage(Message& m)
   at System.Windows.Forms.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

while the small rearrangement of the code


    ContractZaaidatumArticleEntity cza = new ContractZaaidatumArticleEntity();
    cza.Perceel = new PerceelEntity(14);
    m_currentContractZaaidatum.ContractZaaidatumArticle.Add(cza);

works perfectly as expected. As stated above, now whenever I set the Perceel subobject, i first remove my cza from the m_currentContractZaaidatum.ContractZaaidatumArticle , and then add it after setting the perceel. This works as a temporary workaround.


    m_currentContractZaaidatum.ContractZaaidatumArticle.Remove(cza);
    cza.Perceel = new PerceelEntity(14);
    m_currentContractZaaidatum.ContractZaaidatumArticle.Add(cza);

I hope i can regenerate this in a simpler testcase, as the datamodel at this point is getting quite complex with heaps of relations and databinding stuff smile

UPDATE: I have set a breakpoint in ContractZaaidatumEntityBase.cs on the following code


private void DesetupSyncPerceel(bool signalRelatedEntity)
{
    if(_perceel != null)
    {

        
        // disconnect the entity from this entity
        _perceel.AfterSave-=new EventHandler(OnEntityAfterSave);
        if(signalRelatedEntity)
        {
            _perceel.UnsetRelatedEntity(this, "ContractZaaidatumArticle");
        }
*BREAKPOINT*        base.UnsetEntitySyncInformation("Perceel", _perceel, ContractZaaidatumArticleEntity.Relations.PerceelEntityUsingPlId);
        
            SetNewFieldValue((int)ContractZaaidatumArticleFieldIndex.PlId, null, false);
        _perceel = null;
    }
}

Now when i execute


    ContractZaaidatumArticleEntity cza = new ContractZaaidatumArticleEntity();
    m_currentContractZaaidatum.ContractZaaidatumArticle.Add(cza);
    cza.Perceel = new PerceelEntity(14);

my breakpoint get hit time after time , with bool signalRelatedEntity alternating true & false The 7th time the breakpoint is hit, the parameter _perceel is null. The stacktrace at that time is :


>   agro.datalayer.dll!Agro.Datalayer.EntityClasses.ContractZaaidatumArticleEntityBase.DesetupSyncPerceel(bool signalRelatedEntity = true) Line 1331    C#
    agro.datalayer.dll!Agro.Datalayer.EntityClasses.ContractZaaidatumArticleEntityBase.SetupSyncPerceel( SD.LLBLGen.Pro.ORMSupportClasses.IEntity relatedEntity = {Agro.Datalayer.EntityClasses.PerceelEntity}) Line 1360   C#
    agro.datalayer.dll!Agro.Datalayer.EntityClasses.ContractZaaidatumArticleEntityBase.SetRelatedEntity( SD.LLBLGen.Pro.ORMSupportClasses.IEntity relatedEntity = {Agro.Datalayer.EntityClasses.PerceelEntity}, string fieldName = "Perceel") Line 408  C#
    [<Non-user Code>]   
    agro.datalayer.dll!Agro.Datalayer.EntityClasses.PerceelEntityBase.SetRelatedEntity( SD.LLBLGen.Pro.ORMSupportClasses.IEntity relatedEntity = {Agro.Datalayer.EntityClasses.ContractZaaidatumArticleEntity}, string fieldName = "ContractZaaidatumArticle") Line 745 + 0xc bytes C#
    agro.datalayer.dll!Agro.Datalayer.EntityClasses.ContractZaaidatumArticleEntityBase.set_Perceel( Agro.Datalayer.EntityClasses.PerceelEntity value = {Agro.Datalayer.EntityClasses.PerceelEntity}) Line 2061  C#
    agro.forms.dll!Agro.Forms.ZaaiDatumsControl.btnToevoegenVerkoopsartikel_Click(System.Object sender = {Text="Nieuw Toevoegen"}, System.EventArgs e = {System.EventArgs}) Line 705    C#

this is one tough nut to crack stuck_out_tongue_winking_eye

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39933
Joined: 17-Aug-2003
# Posted on: 10-Oct-2005 23:05:30   

Please create a repro case for me, as your situation IMHO goes wrong mainly through custom code being added somewhere so it's IMHO easier to have a repro case so I can check that myself. simple_smile

Frans Bouma | Lead developer LLBLGen Pro
HcD avatar
HcD
User
Posts: 214
Joined: 12-May-2005
# Posted on: 12-Oct-2005 00:12:43   

Ok, this one was really a LOT harder to reproduce then i thought. But i could minimize the reprocase really nice, again in 5 easy steps wink _If the names of the tables don't make sense, it's because i filtered out a LOT of unneeded tables like Article,Contract, etc..which i found irrelevant to recreating the error. But the names really DO make sense in the larger model wink _ STEP1: In SQL server create 3 simple tables in a new database - a Perceel table, with primary key PlId, and a PlName textfield - a ContractZaaiDatum table with primary key CzID , and a CzDatum datetime - a ContractZaaiDatumArticle table with primary key CzaId,and foreign keys PlId and CzId. Set the foreing key constraints in the "manage relations" dialog for ContractZaaiDatumArticle. IMPORTANT : the foreign key PlId has "allow nulls" on. (After hours and hours of testing and cursing i found out that this "allow nulls" is the culprit, if you do net set it, there is no crash in step 5) STEP2: Generate the datalayer in LLBL 1.0.2004.2 using yesterday's "Templates_10102005.zip" in SelfServicing Full/Safe for VS2003 STEP3: In ContractZaaiDatumArticleEntity.cs add the following code


// __LLBLGENPRO_USER_CODE_REGION_START CustomEntityCode
public string PerceelName
{
    get
    {
        return this.Perceel.PlName;
    }
}
// __LLBLGENPRO_USER_CODE_REGION_END

and compile the datalayer STEP4: Make a new Windows Application project, and reference the datalayer, add a app.config, set the correct Main.ConnectionString key. In the form, add a button and a textbox On the buttonclick handler, add the code


private void button1_Click(object sender, System.EventArgs e)
{
    ContractZaaidatumEntity m_currentContractZaaidatum = new ContractZaaidatumEntity();
    textBox1.DataBindings.Add("text",m_currentContractZaaidatum.ContractZaaiDatumArticle,"PerceelName");
    ContractZaaiDatumArticleEntity cza = new ContractZaaiDatumArticleEntity();
    m_currentContractZaaidatum.ContractZaaiDatumArticle.Add(cza);
    cza.Perceel = new PerceelEntity();
}

The databinding is also imperative for generating the bug, omit it and there is no crash STEP5: Run the program and click button1 boom


An unhandled exception of type 'System.NullReferenceException' occurred in sd.llblgen.pro.ormsupportclasses.net11.dll

Additional information: Object reference not set to an instance of an object.
    [<Non-user Code>]   
>   bugtest2.dll!Bugtest2.EntityClasses.ContractZaaiDatumArticleEntityBase.DesetupSyncPerceel(bool signalRelatedEntity = true) Line 982 C#
    bugtest2.dll!Bugtest2.EntityClasses.ContractZaaiDatumArticleEntityBase.SetupSyncPerceel(SD.LLBLGen.Pro.ORMSupportClasses.IEntity relatedEntity = {Bugtest2.EntityClasses.PerceelEntity}) Line 1009  C#
    bugtest2.dll!Bugtest2.EntityClasses.ContractZaaiDatumArticleEntityBase.SetRelatedEntity(SD.LLBLGen.Pro.ORMSupportClasses.IEntity relatedEntity = {Bugtest2.EntityClasses.PerceelEntity}, string fieldName = "Perceel") Line 340 C#
    [<Non-user Code>]   
    bugtest2.dll!Bugtest2.EntityClasses.PerceelEntityBase.SetRelatedEntity(SD.LLBLGen.Pro.ORMSupportClasses.IEntity relatedEntity = {Bugtest2.EntityClasses.ContractZaaiDatumArticleEntity}, string fieldName = "ContractZaaiDatumArticle") Line 326 + 0xf bytes    C#
    bugtest2.dll!Bugtest2.EntityClasses.ContractZaaiDatumArticleEntityBase.set_Perceel(Bugtest2.EntityClasses.PerceelEntity value = {Bugtest2.EntityClasses.PerceelEntity}) Line 1382   C#
    WindowsApplication1.exe!WindowsApplication1.Form1.button1_Click(System.Object sender = {Text="button1"}, System.EventArgs e = {System.EventArgs}) Line 108  C#
    [<Non-user Code>]   
    WindowsApplication1.exe!WindowsApplication1.Form1.Main() Line 99    C#

Hope this helps !

And now off to bed, i promised my wife for once i'd be going before midnight ... missed the deadline again smile

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39933
Joined: 17-Aug-2003
# Posted on: 12-Oct-2005 10:18:28   

Poor wife simple_smile

Thanks for the repro, I'll try it out a.s.a.p. simple_smile

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39933
Joined: 17-Aug-2003
# Posted on: 12-Oct-2005 15:52:28   

The problem triggered by databinding is that databinding will fetch the collection as soon as you add one item to it, and in that case pull Perceel as well. They don't exist (or they do, doesn't matter), you get a Perceel entity in the Cza entity.

Setting it to a new perceel entity, has to detach the old one. The code behind the scenes to clean up all the syncing info and event handlers has code in the wrong order, at least for this situation: it notifies the Cza collection in the old Perceel entity, that the cza entity has to be removed (as perceel is detached from it). So in there, the code notifies the Cza entity that a perceel entity has been detatched from it, (it already knew that, but that's not always the case, hence this generic path). The thing now is that THAT code sets _perceel to null, and the routine originally notifying the Perceel entity that it has to be detached thinks _perceel isn't yet null, but it is.

I think this syncing code finally has come to the stage were it needs a serious refactoring, or at least some re-evaluation. It was already complex, but with the additional patches to make the process more usable in databinding scenarios (so events are thrown here and there), how ironic, makes it even more complex, and I wonder if it cant be simplified and more solid.

I can reschedule a statement, which fixes this problem. I'll do that in the templates and release it as a hotfix. I'll re-evaluate the sync code in 1.0.2005.1.

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39933
Joined: 17-Aug-2003
# Posted on: 12-Oct-2005 16:25:07   

I've uploaded a hotfix for this issue. Please let me know if this fixes your problem. It's available in the templates section, right below the full template package.

Frans Bouma | Lead developer LLBLGen Pro
HcD avatar
HcD
User
Posts: 214
Joined: 12-May-2005
# Posted on: 12-Oct-2005 18:36:14   

So far it looks all ok !!! i will more thoroughly test the whole application to see if there are no other issues popping up .. i definately have to reserve some time to create unittests on the next project wink

But i have a new bug smile (in LLBLGenPro itself - it was probably in there before but i just found it now) I can reproduce it simply as follows in 5 easy steps simple_smile STEP1 I open my .lgp project file. STEP2 Press F7 or choose "Project/Generate" in the menu STEP3 Click "Create participating object subset..." to open the dialog and just click "Ok" STEP4 repeat step 3 once STEP5 Click "start generate" BOOM


Item has already been added.  Key in dictionary: "ResourceCodeLocale"  Key being added: "ResourceCodeLocale"
-----[Core exception]--------------------
   at System.Collections.SortedList.Add(Object key, Object value)
   at SD.LLBLGen.Pro.TDLInterpreter.Interpreter.set_Entities(ArrayList value)
   at SD.LLBLGen.Pro.TaskPerformers.CodeEmitter.Perform(IGenerator executingGenerator, ITask taskDefinition, Hashtable parameters)
   at SD.LLBLGen.Pro.GeneratorCore.Task.Perform(IGenerator executingGenerator, LogNode parentNode)
   at SD.LLBLGen.Pro.GeneratorCore.TaskGroup.Perform(IGenerator executingGenerator, LogNode parentNode)
   at SD.LLBLGen.Pro.GeneratorCore.TaskGroup.Perform(IGenerator executingGenerator, LogNode parentNode)
   at SD.LLBLGen.Pro.GeneratorCore.Generator.Start(ITaskGroup tasksToExecute, Project projectDefinition, TemplateSetDefinition templateSet, ApplicationConfiguration configurationSettings)
   at SD.LLBLGen.Pro.Gui.Forms.MainWindow.StartGeneratorProcess()

It was really accidentally that i found this bug, I was "doublechecking" stuff before regeneration simple_smile But when i do step3 only once all is ok. So i guess this is only a very minor thingie, but still worth mentioning.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39933
Joined: 17-Aug-2003
# Posted on: 12-Oct-2005 19:14:01   

HcD wrote:

So far it looks all ok !!! i will more thoroughly test the whole application to see if there are no other issues popping up .. i definately have to reserve some time to create unittests on the next project wink

So you can make the deadline tonight wink stuck_out_tongue_winking_eye

Thanks for testing and going through all the effort to reproduce it.

But i have a new bug smile (in LLBLGenPro itself - it was probably in there before but i just found it now) I can reproduce it simply as follows in 5 easy steps simple_smile

I'm starting to fear these 5 steps wink

I reproduced it. Thanks, I'll fix it in the 1.0.2005.1 as it's a rare issue.

It was really accidentally that i found this bug, I was "doublechecking" stuff before regeneration simple_smile But when i do step3 only once all is ok. So i guess this is only a very minor thingie, but still worth mentioning.

No problem, keep them coming simple_smile

Frans Bouma | Lead developer LLBLGen Pro
1  /  2