strange error when using UOW

Posts   
 
    
omar avatar
omar
User
Posts: 569
Joined: 15-Oct-2004
# Posted on: 27-Sep-2006 12:47:39   

I have an OrdersEntity that has OrderDetailsCollection with 3 OrderDetailsEntity objects.

m_ordersEntity.OderDate = #9/15/1967#
uow.AddForDelete(m_ordersEntity.OrderDetailsCollection(1))
uow.AddForSave(m_ordersEntity, refetch:=True) 
uow.Commit(adapter, autoCommit:=True)

this code produces the following exception. Am I using UOW in a wroong way here?? Type: System.ArgumentNullException Message: fieldsPersistenceInfo can't be null. Parameter name: fieldsPersistenceInfo Source: SD.LLBLGen.Pro.ORMSupportClasses.NET20 Target Method: SD.LLBLGen.Pro.ORMSupportClasses.IActionQuery CreateUpdateDQ(SD.LLBLGen.Pro.ORMSupportClasses.IEntityFieldCore[], SD.LLBLGen.Pro.ORMSupportClasses.IFieldPersistenceInfo[], System.Data.IDbConnection, System.Collections.Generic.List`1[SD.LLBLGen.Pro.ORMSupportClasses.IPredicate])

Call Stack: Method Name: SD.LLBLGen.Pro.ORMSupportClasses.IActionQuery CreateUpdateDQ(SD.LLBLGen.Pro.ORMSupportClasses.IEntityFieldCore[], SD.LLBLGen.Pro.ORMSupportClasses.IFieldPersistenceInfo[], System.Data.IDbConnection, System.Collections.Generic.List`1[SD.LLBLGen.Pro.ORMSupportClasses.IPredicate]) File Name: Column: 0 Line: 0 CIL Offset: 62 Native Offset: 268

Method Name: SD.LLBLGen.Pro.ORMSupportClasses.IActionQuery CreateUpdateDQ(SD.LLBLGen.Pro.ORMSupportClasses.IEntity2, SD.LLBLGen.Pro.ORMSupportClasses.IFieldPersistenceInfo[], System.Collections.Generic.List`1[SD.LLBLGen.Pro.ORMSupportClasses.IPredicate])
    File Name: 
    Column: 0
    Line: 0
    CIL Offset: 26
    Native Offset: 110

Method Name: Boolean PersistQueue(System.Collections.Generic.List`1[SD.LLBLGen.Pro.ORMSupportClasses.ActionQueueElement`1[ SD.LLBLGen.Pro.ORMSupportClasses.IEntity2]], Boolean)
    File Name: 
    Column: 0
    Line: 0
    CIL Offset: 589
    Native Offset: 1671

Method Name: Void Commit(SD.LLBLGen.Pro.ORMSupportClasses.IDataAccessAdapter, Boolean)
    File Name: 
    Column: 0
    Line: 0
    CIL Offset: 1010
    Native Offset: 2749

Method Name: Void DataPortal_Update()
    File Name: 
    Column: 0
    Line: 0
    CIL Offset: 69
    Native Offset: 218

Inner Exception(s)

Custom Properties ParamName: fieldsPersistenceInfo

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 27-Sep-2006 15:52:43   

What's the version / build of the runtime libraries (right click on ormsupport classes dl -> properties -> version tab -> File version ) ?

omar avatar
omar
User
Posts: 569
Joined: 15-Oct-2004
# Posted on: 27-Sep-2006 20:24:27   

This is version 2.0.0.060921 which I downloaded today from LLBL's page (the 23rd sep download).

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39927
Joined: 17-Aug-2003
# Posted on: 27-Sep-2006 20:50:12   

Can you save the entity normally, without the uow? I think it's related to the fact that DBSpecific and DBGeneric project aren't in sync. (i.e. a field is added to the entity, it's present in the fieldlist, but it's persistenceinfo isn't present in the fieldpersistenceinfo set)

Frans Bouma | Lead developer LLBLGen Pro
omar avatar
omar
User
Posts: 569
Joined: 15-Oct-2004
# Posted on: 27-Sep-2006 21:07:32   

Otis wrote:

Can you save the entity normally, without the uow? I think it's related to the fact that DBSpecific and DBGeneric project aren't in sync. (i.e. a field is added to the entity, it's present in the fieldlist, but it's persistenceinfo isn't present in the fieldpersistenceinfo set)

I dont know If I fully follow what you mean here. What I have done after reading this is: 1- open the LLBL project, refreshed it and regenerated the DAL 2- Made sure my BL references the new DAL dlls 3- tried to save my entity using normal adapter code

m_ordersEntity.Freight = 6.9D
adapter.SaveEntity(m_ordersEntity, True)

Still I am getting the same error frowning

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 28-Sep-2006 07:40:02   

As a trial:

Would you please delete all the DBSpecific DLLs found on your machine (GAC, TEMP ASP.NET folders, Bin folder..etc)

Then let your BL reference the generated projects (add them to the same solution) rather than referencing the DLLs, and then Re-Build.

omar avatar
omar
User
Posts: 569
Joined: 15-Oct-2004
# Posted on: 28-Sep-2006 08:17:43   

Walaa wrote:

As a trial:

Would you please delete all the DBSpecific DLLs found on your machine (GAC, TEMP ASP.NET folders, Bin folder..etc)

Then let your BL reference the generated projects (add them to the same solution) rather than referencing the DLLs, and then Re-Build.

Just did what you suggested and still I am getting the same error. What I dont understand is that all what I am doing here is simple get an OrdersEntity from the DB, update one of its fields and then try to save it back to the DB. I never had something like this with LLBL and thats whats causing me to run in loops

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39927
Joined: 17-Aug-2003
# Posted on: 28-Sep-2006 10:40:39   

Could you please check if all the fields for order are enlisted in the method PersistenceInfoProvider.cs/vb -> InitOrderEntityMappings() ?

It seems that there is a field missing there.

Frans Bouma | Lead developer LLBLGen Pro
omar avatar
omar
User
Posts: 569
Joined: 15-Oct-2004
# Posted on: 28-Sep-2006 15:27:59   

Otis wrote:

Could you please check if all the fields for order are enlisted in the method PersistenceInfoProvider.cs/vb -> InitOrderEntityMappings() ?

It seems that there is a field missing there.

NOP.. all is ok in PersistenceInfoProvider.vb as it has all the info for all the Orders table's columns. Doing further investigation I found the following:

The following code executes with no problem

      Dim app As String = "Server=.\SQLExpress;Database=JCLNorthwind;Trusted_Connection=True"

      Dim oe As OrdersEntity = New OrdersEntity(11131)

      Using adapter As IDataAccessAdapter = New DataAccessAdapter(app)

         If adapter.FetchEntity(oe, CreateOrderDetailsCollectionPrefetchPath) Then
            oe.Freight = 1.25D
            adapter.SaveEntity(oe, True)
         End If

      End Using

The following code gives the same error.

      Dim app As String = "Server=.\SQLExpress;Database=JCLNorthwind;Trusted_Connection=True"

      Dim oe As OrdersEntity = New OrdersEntity(11131, New OrdersEntityValidator)

      Using adapter As IDataAccessAdapter = New DataAccessAdapter(app)

         If adapter.FetchEntity(oe, CreateOrderDetailsCollectionPrefetchPath) Then
            oe.Freight = 1.25D
            adapter.SaveEntity(oe, True)
         End If

      End Using

The only difference between both code listings is that the (oe) object has a Validator object in the 2nd listing. The OrdersEntityValidator is blank and does not have any methods!!

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39927
Joined: 17-Aug-2003
# Posted on: 28-Sep-2006 16:50:32   

Can't reproduce it:


[Test]
public void OrderRecursiveSaveWithValidator()
{
    using(DataAccessAdapter adapter = new DataAccessAdapter())
    {
        adapter.CatalogNameToUse = "Northwind2";
        adapter.CatalogNameUsageSetting = CatalogNameUsage.ForceName;

        OrderEntity o = new OrderEntity(10254, new OrderValidator());
        PrefetchPath2 path = new PrefetchPath2((int)EntityType.OrderEntity);
        path.Add(OrderEntity.PrefetchPathOrderDetails);
        Assert.IsTrue(adapter.FetchEntity(o, path));
        o.Freight += 0.1M;
        Assert.IsTrue(adapter.SaveEntity(o, true));
    }
}

//...

    public class OrderValidator : ValidatorBase
    {
    }

I also don't think it's related.

Have you overriden GetFieldPersistenceInfos in DataAccessAdapter ? If not, could you override it in the DataAccessAdapter class for testing, and FIRST call the base' method and then check in the debugger if it returns any persistence info for OrdersEntity ? (there are a couple of overloads, you should override protected virtual IFieldPersistenceInfo[] GetFieldPersistenceInfos( IEntity2 entity )

The error is related to the fact that NO persistence info is returned from the method GetFieldPersistenceInfos, as null is passed to the CreateUpdateDQ method.

Frans Bouma | Lead developer LLBLGen Pro
omar avatar
omar
User
Posts: 569
Joined: 15-Oct-2004
# Posted on: 28-Sep-2006 22:04:50   

This thing is really getting me scrach my head. I did as you suggested and whenever the fetched entity has a validator I get the error, otherwise all is OK.

Code that executes with the error

Imports SD.LLBLGen.Pro.ORMSupportClasses
Imports DAL
Imports DAL.EntityClasses
Imports DAL.HelperClasses
Imports DAL.DatabaseSpecific

Module Module1

   Sub Main()

      Dim app As String = "Server=.\SQLExpress;Database=JCLNorthwind;Trusted_Connection=True"
      Using adapter As IDataAccessAdapter = New DataAccessAdapter(app)

         Dim oe As OrdersEntity = New OrdersEntity(11131, New OrdersEntityValidator) '=>has validator

         If adapter.FetchEntity(oe, CreateOrderDetailsCollectionPrefetchPath) Then
            oe.Freight = oe.Freight.Value + 0.1D
            If adapter.SaveEntity(oe, True) Then
               Console.WriteLine("Saved OK")
            Else
               Console.WriteLine("NOT Saved")
            End If
         End If

      End Using
      Console.ReadLine()
   End Sub

   Public Function CreateOrderDetailsCollectionPrefetchPath() As IPrefetchPath2
      Dim toReturn As IPrefetchPath2 = New PrefetchPath2(EntityType.OrdersEntity)
      toReturn.Add(OrdersEntity.PrefetchPathOrderDetailsCollection)

      Return toReturn
   End Function
End Module

<Serializable()> Public Class OrdersEntityValidator
   Inherits ValidatorBase
End Class

The code that executes OK


Imports SD.LLBLGen.Pro.ORMSupportClasses
Imports DAL
Imports DAL.EntityClasses
Imports DAL.HelperClasses
Imports DAL.DatabaseSpecific

Module Module1

   Sub Main()

      Dim app As String = "Server=.\SQLExpress;Database=JCLNorthwind;Trusted_Connection=True"
      Using adapter As IDataAccessAdapter = New DataAccessAdapter(app)

         Dim oe As OrdersEntity = New OrdersEntity(11131) '=>NO validator

         If adapter.FetchEntity(oe, CreateOrderDetailsCollectionPrefetchPath) Then
            oe.Freight = oe.Freight.Value + 0.1D
            If adapter.SaveEntity(oe, True) Then
               Console.WriteLine("Saved OK")
            Else
               Console.WriteLine("NOT Saved")
            End If
         End If

      End Using
      Console.ReadLine()
   End Sub

   Public Function CreateOrderDetailsCollectionPrefetchPath() As IPrefetchPath2
      Dim toReturn As IPrefetchPath2 = New PrefetchPath2(EntityType.OrdersEntity)
      toReturn.Add(OrdersEntity.PrefetchPathOrderDetailsCollection)

      Return toReturn
   End Function
End Module

The only difference between the two console applications is the (oe) object having a validator object. This behaviour is consistant and I managed to reporoduce it in a Console test harness!! I have no idea why this thing is happening and cant understand why the adaptre's GetFieldPersistenceInfos() returns a NULL array when the entity has a validator but returns a proper populated array when the entity has no validator object.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39927
Joined: 17-Aug-2003
# Posted on: 28-Sep-2006 22:21:18   

So the GetFieldPersistenceInfos() method indeed does return null/Nothing ? Could you try with a debug build of the ORMSupportClasses dll and step into that method please? If you don't succeed in this or if it's too much of a hassle, could you mail me the testproject you made, WITH .lgp file and generated code to support AT llblgen.com and I'll have a look with a debug build. ?

Frans Bouma | Lead developer LLBLGen Pro
omar avatar
omar
User
Posts: 569
Joined: 15-Oct-2004
# Posted on: 28-Sep-2006 23:25:33   

After build a debug version of LLBLSupport and rebuilding the DAL dlls using the debug version of LLBLSupport.

Found the problem in this function

        protected virtual IFieldPersistenceInfo[] GetFieldPersistenceInfos( IEntity2 entity )
        {
            if( _persistenceInfoProvider == null )
            {
                throw new ApplicationException( "The IPersistenceInfoProvider object of this DataAccessAdapter is null. " );
            }
            for( int i = 0; i < entity.Fields.Count; i++ )
            {
                InsertPersistenceInfoObjects( entity.Fields[i] );
            }
            return _persistenceInfoProvider.GetAllFieldPersistenceInfos( entity );
        }

The last line of the function calls the following function

        public IFieldPersistenceInfo[] GetAllFieldPersistenceInfos( IEntity2 entity )
        {
            return GetAllFieldPersistenceInfos( entity.LLBLGenProEntityName );
        }

The problem being that the LLBLGenProEntityName is an empty string when the test code has a validator for the entity BUT it has the proper entity name when the test code does NOT have a Validator for the entity..

omar avatar
omar
User
Posts: 569
Joined: 15-Oct-2004
# Posted on: 28-Sep-2006 23:35:57   

Ok.. new finding.. if you break at the line

adapter.SaveEntity(oe, True)

in your test code I get the following If (oe) has a Validator object, its oe.LLBLGenProEntityName is an empty string while when (oe) does NOT have a validator object its oe.LLBLGenProEntityName returns the correct entity name string "OrdersEntity"

omar avatar
omar
User
Posts: 569
Joined: 15-Oct-2004
# Posted on: 29-Sep-2006 00:00:57   

FOUND IT!!! simple_smile

Its a bug in the Entity template in the following constructor

This constructor starts by calling MyBase.New("OrdersEntity")

        Public Sub New(orderID As System.Int32)
            MyBase.New("OrdersEntity")
            InitClassEmpty(CreateValidator(), CreateFields())
            Me.OrderID = orderID
        End Sub

This constructor DOES NOT call MyBase.New("OrdersEntity")

        Public Sub New(orderID As System.Int32, validator As IValidator)
            InitClassEmpty(validator, CreateFields())
            Me.OrderID = orderID
        End Sub

so whenever an entity is instantiated with a validator, its LLBLGenProEntityName property was an empty string!!

that took me 2 days to find but could not do it without your help... thanks man!!

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39927
Joined: 17-Aug-2003
# Posted on: 29-Sep-2006 11:05:43   

OK! simple_smile

It's a VB.NET only issue, hence the reason I didn't find it! Great catch and sorry you had to wade through this for 2 long days, but I'm glad it's solved now simple_smile . I'll fix this a.s.a.p. and it's available in the next build (later today)

There's another constructor as well which doesn't work properly, the empty constructor for a new subtyped entity.

Frans Bouma | Lead developer LLBLGen Pro