DataScope - Exception expected

Posts   
 
    
Puser
User
Posts: 228
Joined: 20-Sep-2012
# Posted on: 20-Jul-2018 16:48:55   

Hi using 5.3.1 with llblgen pro runtime library and adapter

I have a Contract entity which has a 1-1..0 relationship with a ContractMemo entity. This ContractMemo is a subtype of Note with a Discriminator value and is of type Target per entity hierarchy.

Now I create a new Contract entity and attach it to a new DataScope. Then I fill some properties and then I add a new ContractMemoEntity to the Contract property 'ContractMemo' (and fill (or dont fill) the Text property within that). Now the datascope has the changes (confirmed with event ContainedDataChanged). I expect both entities to be created when calling CommitChangesAsync(adapter). But nothing happens and the result of CommitChangesAsync(..) is false. Also no Exception, which could indicate some error.

Now when I create the Contract entity, fill some properties and add a new ContractMemoEntity to the Contract.ContractMemo property first and then add it to the DataScope and call CommitChangesAsync(.) it works....

I'm puzzled.... and it took me a looooooooong time to find this out.

PS: I use datascope to track changes (updates, deletes) along the way so I need to put these in first or else changes/deletes don't get picked up.

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 23-Jul-2018 01:09:58   

But nothing happens and the result of CommitChangesAsync(..) is false. Also no Exception, which could indicate some error.

Could you please check if there are SQL queries generated/executed? And if so, could you please run them against the database to see if they execute without errors.

Also as I couldn't reproduce it, could you please post the smallest code snippet possible that produces this issue. Is it reproducible between any 1:1...0 relation, or maybe 1:m? Does it require an inheritance hierarchy in the 1...0 of the relation to be reproduced?

Puser
User
Posts: 228
Joined: 20-Sep-2012
# Posted on: 25-Jul-2018 12:38:31   

Indeed no SQL statements in ORM Profiler.

I dont have time to create the model and projects as you would wish, but I managed to get things working by adjusting the template quite a bit, but I dont know what the side effects would be....... rage

see below adding of code: ActiveContext?.Add(value);


        public virtual ContractMemoEntity ContractMemo
        {
            get { return _ContractMemo; }
            set
            {
                if(this.IsDeserializing)
                {
                    SetupSyncContractMemo(value);
                    CallSetRelatedEntityDuringDeserialization(value, "Contract");
                }
                else
                {
                    if(value==null)
                    {
                        bool raisePropertyChanged = (_ContractMemo !=null);
                        DesetupSyncContractMemo(true, true);
                        if(raisePropertyChanged)
                        {
                            OnPropertyChanged("ContractMemo");
                        }
                    }
                    else
                    {
                        if(_ContractMemo!=value)
                        {
                            ActiveContext?.Add(value); // <--- ADDING THIS MAKES IT WORK
                            ((IEntity2)value).SetRelatedEntity(this, "Contract");
                            SetupSyncContractMemo(value);
                        }
                    }
                }
            }
        }

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 25-Jul-2018 20:13:08   

I didn't ask for a repro project just a code snippet, so we can try to reproduce it.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 26-Jul-2018 09:13:35   

In theory it should be the same thing: adding an entity X to a datascope makes it to be added to a context, which will be the context all related entities will be added to as well.

The line you added shouldn't make a difference as it's an action that's done when the sync info is set. (SetupSyncContractMemo(value) calls into PerformSetupSyncRelatedEntity which sets the related entity's ActiveContext property to the context of the entity, which will add the related entity to the active context. Your approach basically does that too. So its odd that would fix it)

I'll try to reproduce it with the same relationship setup.

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 26-Jul-2018 10:12:45   

I can't reproduce it. This succeeds:


[Test]
public void GraphInsertWithDataScopeTest()
{
    var testRunId = Guid.NewGuid();
    var scope = new AddressDatascope(testRunId);
    var address = EntityCreator.CreateNewAddress(1);
    address.TestRunId = testRunId;
    var customer = EntityCreator.CreateNewCustomer(1);
    scope.Add(address);
    Assert.IsNotNull(address.ActiveContext);
    customer.BillingAddress = address;
    Assert.IsNotNull(customer.ActiveContext);
    customer.VisitingAddress = address;
    customer.TestRunId = testRunId;
    Assert.IsTrue(scope.CommitChanges());
}

Latest 5.3 build (5.3.7). Relationships are 1:1.

Frans Bouma | Lead developer LLBLGen Pro
Puser
User
Posts: 228
Joined: 20-Sep-2012
# Posted on: 26-Jul-2018 11:23:19   

i'm still using 5.3.1 sorry... (i need to change your templates each time after an update so i just cannot update everytime)

see attachment for setup and ormprofiler results

this my code which doesnt do anything:


        public async Task TestAsync()
        {
            var c = new RoyaltyContractEntity();
            c.AantalPresenten = 1;
            _uow.Add(c); // <---- add it early
            var memo = new RoyaltyContractMemoEntity();
            memo.Text = "iets";
            c.RoyaltyContractMemo = memo;
            await _uow.CommitChangesAsync(); //doesn't produce anything: no connection open, no exception
        }

this code works:


        public async Task TestAsync()
        {
            var c = new RoyaltyContractEntity();
            c.AantalPresenten = 1;
            var memo = new RoyaltyContractMemoEntity();
            memo.Text = "iets";
            c.RoyaltyContractMemo = memo;
            _uow.Add(c); // <---- add it late
            await _uow.CommitChangesAsync(); //this works as expected
        }

datascope code:


   public class RoyCtrUnitOfWork : DataScope
    {
        private readonly IDataAccessAdapterFactoryData _adapterFactory;

        public RoyCtrUnitOfWork(IDataAccessAdapterFactoryData adapterFactory)
        {
            _adapterFactory = adapterFactory;
        }

        public void Add(RoyaltyContractEntity toAttach)
        {
            base.Attach(toAttach);
        }

        public async Task CommitChangesAsync(DataScopeRefetchStrategyType refetchStrategy = DataScopeRefetchStrategyType.DoNothing)
        {
            base.RefetchStrategy = refetchStrategy;

            using (var adapter = _adapterFactory.CreateDataAccessAdapter())
            {
                var result = await base.CommitChangesAsync(adapter).ConfigureAwait(false);
            }
        }
    }

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 26-Jul-2018 13:11:00   

I'd rather not open a word doc from an outside source, what's in the docx exactly? If it's a screenshot, just attach it to the post instead of the word doc.

Frans Bouma | Lead developer LLBLGen Pro
Puser
User
Posts: 228
Joined: 20-Sep-2012
# Posted on: 26-Jul-2018 13:25:41   

several screenshots yes....

I'll copy them different files then....

Puser
User
Posts: 228
Joined: 20-Sep-2012
# Posted on: 26-Jul-2018 13:26:40   

blaa

Attachments
Filename File size Added on Approval
t1.png 43,594 26-Jul-2018 13:26.54 Approved
t2.png 27,741 26-Jul-2018 13:26.58 Approved
Puser
User
Posts: 228
Joined: 20-Sep-2012
# Posted on: 26-Jul-2018 13:27:18   

bllaaa

Attachments
Filename File size Added on Approval
t3.png 19,188 26-Jul-2018 13:27.23 Approved
Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 26-Jul-2018 19:52:53   

Thanks for the code snippet and screen shots.

Could you please find out the answers of the following?

Walaa wrote:

Is it reproducible between any 1:1...0 relation, or maybe 1:m? Does it require an inheritance hierarchy in the 1...0 of the relation to be reproduced?

Puser
User
Posts: 228
Joined: 20-Sep-2012
# Posted on: 26-Jul-2018 22:16:09   

Is it reproducible between any 1:1...0 relation, or maybe 1:m?

It's a 1:1...0 relation as can be seen from screen shot. I have no problems with 1:n relations.

Does it require an inheritance hierarchy in the 1...0 of the relation to be reproduced?

I try to understand what you ask: Non-inheritance 1...0 relations work.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 27-Jul-2018 09:27:41   

We'll look into it. This will be on Monday however.

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 30-Jul-2018 10:14:06   

There must be something small that's wrong as I can't reproduce it on my part, Walaa could though.


[Test]
public void GraphInsertWithDataScopeTest2()
{
    var testRunId = Guid.NewGuid();
    var c = new ContractEntity();
    c.Name = "TestContract";
    var memo = new ContractMemoEntity();
    memo.Info = "Info";
    memo.Content = "Content";
    
    var scope = new ContractDatascope(testRunId);
    scope.Add(c);
    Assert.IsNotNull(c.ActiveContext);
    Assert.IsNull(memo.ActiveContext);
    c.Memo = memo;
    Assert.IsNotNull(memo.ActiveContext);
    Assert.IsTrue(scope.CommitChanges());
}


[Test]
public void GraphInsertWithDataScopeTest3()
{
    var testRunId = Guid.NewGuid();
    var c = new ContractEntity();
    c.Name = "TestContract";
    var memo = new ContractMemoEntity();
    memo.Info = "Info";
    memo.Content = "Content";
    c.Memo = memo;
    
    var scope = new ContractDatascope(testRunId);
    scope.Add(c);
    Assert.IsNotNull(c.ActiveContext);
    Assert.IsNotNull(memo.ActiveContext);
    Assert.IsTrue(scope.CommitChanges());
}   

Contract is normal entity, ContractMemo is subtype in TPEH hierarchy of Note, with model only 1:1 relationship with Contract, with nullable FK (as it's 1:1..0).

Both tests succeed. This is very strange. (I used 5.3.7). I'll also look into Walaa's repro to see what's different.

Frans Bouma | Lead developer LLBLGen Pro
Puser
User
Posts: 228
Joined: 20-Sep-2012
# Posted on: 31-Jul-2018 11:03:01   

Same results with 5.4.2:

  • ActiveContext of Memo is indeed null:

Console.WriteLine(memo.ActiveContext == null); // --> true

Contract is normal entity, ContractMemo is subtype in TPEH hierarchy of Note, with model only 1:1 relationship with Contract, with nullable FK (as it's 1:1..0).

I don't know if it's just semantics... the FK Key1 in the Notes table isnt nullable. A note cannot exist without a parent (in this case Contract). There can be 0 or 1 (general) note for the contract, therefore 1:1..0 So the navigator property ContractMemo in the ContractEntity is nullable.

Puser
User
Posts: 228
Joined: 20-Sep-2012
# Posted on: 31-Jul-2018 11:52:35   

so strange. After setting RoyaltyContractMemo property the ActiveContext of the RoyaltyContractEntity is being reset to null:

        public async Task Test3DoesntWorkAsync()
        {
            var c = new RoyaltyContractEntity();
            c.AantalPresenten = 2;
            var memo = new RoyaltyContractMemoEntity();
            memo.Text = "iets";
            _uow.Add(c); // <---- add it early, doesnt work
            Console.WriteLine(c.ActiveContext == null); //--> false
            c.RoyaltyContractMemo = memo;
            Console.WriteLine(c.ActiveContext == null); //--> true??? ActiveContext reset to null after setting RoyaltycontractMemo property... why?
            Console.WriteLine(memo.ActiveContext == null); //--> true

            var success = await _uow.CommitChangesAsync();
            Console.WriteLine(success ? "Gelukt" : "MIslukt");
        }
Puser
User
Posts: 228
Joined: 20-Sep-2012
# Posted on: 31-Jul-2018 12:38:23   

...testing with opposite navigator does work, but isnt the normal supposed way to work with the entities.

        public async Task Test6WorksAsync()
        {
            var c = new RoyaltyContractEntity();
            c.AantalPresenten = 2;
            var memo = new RoyaltyContractMemoEntity();
            memo.Text = "iets";
            _uow.Add(c); // <---- add it early, but testing with opposite navigator (which we dont like to be visible at all)

            Console.WriteLine(c.ActiveContext == null); //--> false
            memo.RoyaltyContract = c; //c.RoyaltyContractMemo = memo;    //REVERSED TO OPPOSING NAVIGATOR HERE
            Console.WriteLine(c.ActiveContext == null); //--> false
            Console.WriteLine(memo.ActiveContext == null); //--> false

            var success = await _uow.CommitChangesAsync();
            Console.WriteLine(success ? "Gelukt" : "MIslukt");
        }
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 01-Aug-2018 09:46:30   

I can reproduce it with Walaa's repro, I can't with mine. I can't see a difference between them, but there must be one simple_smile I indeed see the same behavior as you reported in the last posts: assigning memo will reset the active context.

Must be something to do with resetting the reference. Walaa's repro does have a duplicate FK field mapped, perhaps that's it but your screenshots suggest you don't have that, so I guess that's not the cause, but I'll investigate it. I can now at least debug the situation and see what's going on simple_smile

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 01-Aug-2018 10:04:41   

The weird thing is, it looks like a bug in v5.4, where it assigns the related entity's context to the left-hand side's entity, which is of course resetting it. However you have a failing test with v5.3 (walaa used v5.4 where it indeed fails).

I can't reproduce it with v5.3, will now see if the same test fails in v5.4

(edit) generating code with v5.3 from Walaa's project and using his tests indeed fails on v5.3 too. confused So it is a bug somewhere but why my tests succeed is a mystery.... disappointed

(edit) migrating the tests to v5.4 still make them succeed. I truly have something backwards in the model but can't find it... confused

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 01-Aug-2018 10:34:51   

Found the difference, I have an empty navigator on the ContractMemo side of the relationship (no idea why, likely forgot to mention one in quickmodel), so it switches to not setting through that entity and it never hits the bug, where it simply tries to assign the context of the related entity to the left-hand-side entity.

Will correct that setup and then fix the bug. simple_smile

(that was it indeed, can repro it now simple_smile )

Frans Bouma | Lead developer LLBLGen Pro
Puser
User
Posts: 228
Joined: 20-Sep-2012
# Posted on: 01-Aug-2018 11:35:06   

Ok thank you Frans. in the meantime I have updated the entityIncludeAdapter.template I'll be on holiday for some weeks and check after.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 01-Aug-2018 11:53:04   

Fixed in v5.3.7 hotfix / 5.4.3 hotfix, now available! simple_smile

Have a great vacation simple_smile

Frans Bouma | Lead developer LLBLGen Pro