Fetch object reference exception w/inherited class

Posts   
 
    
thnk2wn
User
Posts: 31
Joined: 05-Jul-2008
# Posted on: 19-Oct-2008 21:45:19   

Lgen version: 2.6 final (v2.0.50727 runtime)

.NET 3.5, Adapter, General2008, Oracle 9i

I have the below function:


private void FetchCoders3(IDatabaseAdapter adapter)
        {
            LinqMetaData metaData = new LinqMetaData(adapter);
            var q = (from rc in metaData.ReviewersAndCoders
                    join rcbc in metaData.RevCodeBillingCenters on rc.RevCodeId equals rcbc.RevCodeId
                    where rc.RevCodeFlag == "C"
                    orderby rc.Name
                    select new CodersLookup()
                    {
                        Name = rc.Name,
                        RevCodeId = rc.RevCodeId,
                        RevCodeFlag = rc.RevCodeFlag,
                        BillingCenterId = rcbc.BillingCenterId
                    }).Distinct();
            List<CodersLookup> list = q.ToList();
            Debug.WriteLine(list.Count);
        }

(IDatabaseAdapter inherits from IDataAccessAdapter). The CodersLookup class looks like:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using CRMA.Model.EntityClasses;

namespace CRMA.Model.EntityLookups
{
    public class CodersLookup : ReviewersAndCodersEntity
    {
        private long _billingCenterId;

        public CodersLookup()
            : base()
        {
        }

        public long BillingCenterId
        {
            get { return _billingCenterId; }
            set { _billingCenterId = value; }
        }

        public string RevCodeName
        {
            get { return "CODERS"; }
        }

    }
}

Basically the ReviewersAndCodersEntity has everything I need minus the one BillingCenterId field that comes from the related RevCodeBillingCentersEntity. So I decided to just create a new class inheriting from the main entity w/the new class having the additional field(s) I need. When I execute the query I get the below exception:

System.NullReferenceException occurred Message="Object reference not set to an instance of an object." Source="SD.LLBLGen.Pro.LinqSupportClasses.NET35" StackTrace: at SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProProviderBase.CreateResultsContainer(Type containerElementType, IElementCreatorCore generatedCodeElementCreator) at SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProProvider2. SetupProjectionElementsForExecution(QueryExpression toExecute) at SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProProvider2. ExecuteValueListProjection(QueryExpression toExecute) at SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProProviderBase.ExecuteExpression(Expression handledExpression) at SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProProviderBase.Execute(Expression expression) at SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProProviderBase. System.Linq.IQueryProvider.Execute(Expression expression) at SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProQuery1.Execute() at SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProQuery1.System. Collections.Generic.IEnumerable<T>.GetEnumerator() at System.Collections.Generic.List1..ctor(IEnumerable1 collection) at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source) at CRMA.DataAccess.EntitySpecific.Server.LookupDataAdapter.FetchCoders3(IDatabaseAdapter adapter) in C:\Source\CRMA\Dev.Lgen\DAL\CRMA.DataAccess\EntitySpecific\Server\LookupDataAdapter.cs:line 111 InnerException:

If I change the CodersLookup class so it does not inherit from the source generated entity class (and duplicate the properties I was using in the base), the exception goes away. So inheritance appears to be the problem but I am not sure if this is something I can do, and what I might be missing if so?

I had a variation of the query working before with a prefetch path but that effected my distinct operation and I really need the data flat in this case for databinding in the same list. I suppose I could create a view in the database instead but would prefer to avoid that in cases. Assuming I can also use designer to just map in a field or two I need in one entity that happens to reside in another table... my trial just expired (doh) so that's not workable for a few days at least. Any good rules of thumb to assist in choosing between options of combining related data across entities / tables...?

The LINQ trace dump is below:

Initial expression to process: value(SD.LLBLGen.Pro.LinqSupportClasses.DataSource21[ CRMA.Model.EntityClasses.ReviewersAndCodersEntity]).Join(value( SD.LLBLGen.Pro.LinqSupportClasses.DataSource21[ CRMA.Model.EntityClasses.RevCodeBillingCentersEntity]), rc => rc.RevCodeId, rcbc => rcbc.RevCodeId, (rc, rcbc) => new <>f__AnonymousType0`2(rc = rc, rcbc = rcbc)).Where(<>h__TransparentIdentifier1 => (<>h__TransparentIdentifier1.rc.RevCodeFlag = "C")).OrderBy(<>h__TransparentIdentifier1 => <>h__TransparentIdentifier1.rc.Name).Select(<>h__TransparentIdentifier1 => new CodersLookup() {Name = <>h__TransparentIdentifier1.rc.Name, RevCodeId = <>h__TransparentIdentifier1.rc.RevCodeId, RevCodeFlag = <>h__TransparentIdentifier1.rc.RevCodeFlag, BillingCenterId = <>h__TransparentIdentifier1.rcbc.BillingCenterId}).Distinct()

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39861
Joined: 17-Aug-2003
# Posted on: 20-Oct-2008 10:02:45   

You posted the .NET runtime version. Please see the Guidelines thread in this forum for how to obtain the runtime lib version number. In any case: try the latest build from the customer area / latest demo and see if the problem is still there.

Frans Bouma | Lead developer LLBLGen Pro
Svirid
User
Posts: 2
Joined: 20-Oct-2008
# Posted on: 20-Oct-2008 20:30:37   

Have the same problem today ... Pls Help .

Thanks a lot.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39861
Joined: 17-Aug-2003
# Posted on: 20-Oct-2008 21:28:23   

Svirid wrote:

Have the same problem today ... Pls Help .

Thanks a lot.

For you too: please answer my question above. We can't help you unless you give us detailed information. See my previous post.

Frans Bouma | Lead developer LLBLGen Pro
Svirid
User
Posts: 2
Joined: 20-Oct-2008
# Posted on: 21-Oct-2008 11:48:58   

LLBLGen Pro 2.6

SD.LLBLGen.Pro.ORMSupportClasses.NET20.dll 2.6.08.0624 SD.LLBLGen.Pro.DQE.MySql.NET20.dll 2.6.08.0612 SD.LLBLGen.Pro.LinqSupportClasses.NET35.dll 2.6.08.0616 SD.LLBLGen.Pro.TypeConverters.dll 2.6.0.0

We are using template MySQLSpecific.Net20 Version of MySQL 4.1

CoreLab.Data 4.70.23.0 CoreLab.MySql 4.70.31.0

The same situation as you noticed above ... tnx

Walaa avatar
Walaa
Support Team
Posts: 14993
Joined: 21-Aug-2005
# Posted on: 21-Oct-2008 12:29:15   

SD.LLBLGen.Pro.ORMSupportClasses.NET20.dll 2.6.08.0624 SD.LLBLGen.Pro.DQE.MySql.NET20.dll 2.6.08.0612 SD.LLBLGen.Pro.LinqSupportClasses.NET35.dll 2.6.08.0616

A little bit old, and many things have been fixed since then. Would you please try using the latest available release?

thnk2wn
User
Posts: 31
Joined: 05-Jul-2008
# Posted on: 06-Nov-2008 23:13:48   

Sorry for the delay but I am still receiving the original error with the code in the initial thread after trying the updated version. Any ideas?

SD.LLBLGen.Pro.ORMSupportClasses.NET20.dll : 2.6.8.1013 SD.LLBLGen.Pro.LinqSupportClasses.NET35.dll : 2.6.8.1001 SD.LLBLGen.Pro.DQE.Oracle10g.NET20.dll : 2.6.8.1009

.NET 3.5, Adapter, General2008, Oracle 9i

Exception:

System.NullReferenceException occurred Message="Object reference not set to an instance of an object." Source="SD.LLBLGen.Pro.LinqSupportClasses.NET35" StackTrace: at SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProProviderBase.CreateResultsContainer( Type containerElementType, IElementCreatorCore generatedCodeElementCreator) at SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProProvider2. SetupProjectionElementsForExecution( QueryExpression toExecute) at SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProProvider2.ExecuteValueListProjection( QueryExpression toExecute) at SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProProviderBase.ExecuteExpression( Expression handledExpression) at SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProProviderBase.Execute(Expression expression) at SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProProviderBase.System.Linq.IQueryProvider .Execute(Expression expression) at SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProQuery1.Execute() at SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProQuery1.SD.LLBLGen.Pro.LinqSupportClasses .ILLBLGenProQuery.Execute() at CRMA.DataAccess.EntitySpecific.Server.LookupDataAdapter.FetchReviewersCoders( IDatabaseAdapter adapter, String revCodeType) in C:\Source\CRMA\Dev.Lgen\DAL\CRMA.DataAccess\EntitySpecific\LookupDataAdapter.cs:line 102 InnerException:

Output:

Method Enter: DataAccessAdapterBase.ExecuteMultiRowRetrievalQuery
Method Enter: DataAccessAdapterBase.OpenConnection
Method Exit: DataAccessAdapterBase.OpenConnection
Method Exit: DataAccessAdapterBase.ExecuteMultiRowRetrievalQuery
Method Exit: DataAccessAdapterBase.FetchEntityCollectionInternal(7)
Method Exit: DataAccessAdapterBase.FetchEntityCollection(sunglasses
'CRMA.Console.vshost.exe' (Managed): Loaded 'C:\Source\CRMA\Dev.Lgen\CRMA.Console\bin\Debug\SD.LLBLGen.Pro.LinqSupportClasses.NET35.dll'
Initial expression to process: value(SD.LLBLGen.Pro.LinqSupportClasses.DataSource21[CRMA.Model. EntityClasses.ReviewersAndCodersEntity]).Join(value(SD.LLBLGen.Pro .LinqSupportClasses.DataSource21[CRMA.Model.EntityClasses .RevCodeBillingCentersEntity]), rc => rc.RevCodeId, rcbc => rcbc.RevCodeId, (rc, rcbc) => new <>f__AnonymousType0`2(rc = rc, rcbc = rcbc)).Where(<>h__TransparentIdentifier0 => (<>h__TransparentIdentifier0.rc.RevCodeFlag = value(CRMA.DataAccess.EntitySpecific.Server.LookupDataAdapter+<>c__DisplayClass1).revCodeType)).OrderBy(<>h__TransparentIdentifier0 => <>h__TransparentIdentifier0.rc.Name).Select(<>h__TransparentIdentifier0 => new ReviewersAndCodersLookup() {Name = <>h__TransparentIdentifier0.rc.Name, RevCodeId = <>h__TransparentIdentifier0.rc.RevCodeId, RevCodeFlag = <>h__TransparentIdentifier0.rc.RevCodeFlag, BillingCenterId = <>h__TransparentIdentifier0.rcbc.BillingCenterId}).Distinct()

Method with exception:


private EntityCollection<ReviewersAndCodersLookup> FetchReviewersCoders(IDatabaseAdapter adapter,
            string revCodeType)
        {
            EntityCollection<ReviewersAndCodersLookup> collection = null;
            LinqMetaData metaData = new LinqMetaData(adapter);
            ILLBLGenProQuery q = (ILLBLGenProQuery)
                (from rc in metaData.ReviewersAndCoders
                join rcbc in metaData.RevCodeBillingCenters on rc.RevCodeId equals rcbc.RevCodeId
                where rc.RevCodeFlag == revCodeType
                orderby rc.Name
                select new ReviewersAndCodersLookup()
                {
                    Name = rc.Name, RevCodeId = rc.RevCodeId, RevCodeFlag = rc.RevCodeFlag,
                    BillingCenterId = rcbc.BillingCenterId
                }).Distinct();
            collection = q.Execute() as EntityCollection<ReviewersAndCodersLookup>;

            return collection;
        }

The lookup class inheriting from the entity:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using CRMA.Model.EntityClasses;

namespace CRMA.Model.HelperClasses
{
    public class ReviewersAndCodersLookup : ReviewersAndCodersEntity
    {
        private long _billingCenterId;

        public long BillingCenterId
        {
            get { return _billingCenterId; }
            set { _billingCenterId = value; }
        }
    }
}

DDL for the two tables is attached along with full source for a couple of the key files involved...

Attachments
Filename File size Added on Approval
RevCode.zip 14,005 06-Nov-2008 23:14.03 Approved
Walaa avatar
Walaa
Support Team
Posts: 14993
Joined: 21-Aug-2005
# Posted on: 07-Nov-2008 13:16:23   

I'm a little bit confused, sorry.

The ReviewersAndCodersLookup class in the above posted code sample, is it the same thing as the attached CodersLookup class, or are they 2 differrent things?

thnk2wn
User
Posts: 31
Joined: 05-Jul-2008
# Posted on: 07-Nov-2008 15:12:59   

Sorry for the confusion - my fault. CodersLookup was the old version that I should have deleted. RevierwsAndCodersLookup is the new version. Essentially they are same but...

Thanks

Walaa avatar
Walaa
Support Team
Posts: 14993
Joined: 21-Aug-2005
# Posted on: 10-Nov-2008 07:54:43   

Essentially they are same but...

But what? simple_smile Is there anything we should know about?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39861
Joined: 17-Aug-2003
# Posted on: 10-Nov-2008 09:52:45   

Will look into it.

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39861
Joined: 17-Aug-2003
# Posted on: 10-Nov-2008 12:34:28   

Reproduced.

Looking into it.

(edit) The cause is that there's no factory for the ReviewersAndCodersLookup type. Defining an EntityCollection<ReviewersAndCodersLookup > is therefore not possible, there's no factory.

When I fix the issue with the type instantiation, I get a crash with the conversion of EntityCollection<ReviewersAndCodersEntity> to IEnumerable<ReviewersAndCodersLookup> which can't be done, according to the CLR, as it created an EntityCollection<ReviewersAndCodersEntity> because the factory obtained from the ReviewersAndCodersLookup instance dummy created from the ReviewersAndCodersLookup type produces a factory for ReviewersAndCodersEntity.

You're either adviced to do: 1) create a partial class of ReviewersAndCodersEntity and add the property you added to ReviewersAndCodersLookup to that partial class. OR 2) override in ReviewersAndCodersLookup the method: CreateEntityFactory() and in that override return an instance of a derived class of ReviewersAndCodersEntityFactory, which produces ReviewersAndCodersLookup instances instead of ReviewersAndCodersEntity instances.

Example of the latter:

Helper classes:


public class OrderDerived : OrderEntity
{
    public string CompanyName { get; set; }

    protected override IEntityFactory2 CreateEntityFactory()
    {
        return new OrderDerivedFactory();
    }
}


public class OrderDerivedFactory : OrderEntityFactory
{
    public override IEntityCollection2 CreateEntityCollection()
    {
        return new EntityCollection<OrderDerived>(this);
    }

    public override IEntity2 Create()
    {
        return new OrderDerived();
    }
}

Query:


[Test]
public void GetEntitySetUsingProjectionOnDirectEntityType()
{
    using(DataAccessAdapter adapter = new DataAccessAdapter())
    {
        LinqMetaData metaData = new LinqMetaData(adapter);
        var q = from o in metaData.Order
                join c in metaData.Customer on o.CustomerId equals c.CustomerId
                where o.EmployeeId > 4
                orderby o.OrderDate ascending
                select new OrderDerived()
                {
                    OrderId = o.OrderId,
                    CustomerId = o.CustomerId,
                    CompanyName = c.CompanyName,
                    EmployeeId = o.EmployeeId
                };

        int count = 0;
        foreach(var v in q)
        {
            Assert.IsTrue(v.EmployeeId > 4);
            Assert.IsFalse(string.IsNullOrEmpty(v.CompanyName));
            count++;
        }
        Assert.AreEqual(334, count);
    }
}

Personally, I'd go for the partial classes, as that doesn't create parallel hierarchies.

(edit) Please use the attached dll for testing it out.

Frans Bouma | Lead developer LLBLGen Pro
thnk2wn
User
Posts: 31
Joined: 05-Jul-2008
# Posted on: 10-Nov-2008 15:59:51   

I still get the same exception after making the changes for the factory, and the output looks the same as well.

Derived entity class:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using CRMA.Model.EntityClasses;
using SD.LLBLGen.Pro.ORMSupportClasses;
using CRMA.Model.FactoryClasses;

namespace CRMA.Model.EntityClasses
{
    public class ReviewersAndCodersLookup : ReviewersAndCodersEntity
    {
        private long _billingCenterId;

        public long BillingCenterId
        {
            get { return _billingCenterId; }
            set { _billingCenterId = value; }
        }

        protected override IEntityFactory2 CreateEntityFactory()
        {
            return new ReviewersAndCodersLookupFactory();
        }
    }
}

The factory class:


    public partial class ReviewersAndCodersEntityFactory : EntityFactoryBase2
    {
        public override IEntity2 GetNullEntitySurrogate()
        {
            var e = new ReviewersAndCodersEntity(-1);
            e.Name = " ";
            return e;
        }
    }

    public class ReviewersAndCodersLookupFactory : ReviewersAndCodersEntityFactory
    {
        public override IEntityCollection2 CreateEntityCollection()
        {
            return new EntityCollection<ReviewersAndCodersLookup>(this);
        }

        public override IEntity2 Create()
        {
            return new ReviewersAndCodersLookup();
        }
    }

I prefer to go with the factory method as I do not want to "pollute" the original entity with various properties and code that only apply in specific instances. Although I was not aware there was this dependency on the factory class. In the absence of a factory, could it not just new it off using default constructor?

Let me know if there is anything I am missing as far as correcting the code to work. If needed I can do another sample app but the DB will be a problem...

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39861
Joined: 17-Aug-2003
# Posted on: 10-Nov-2008 16:36:32   

You have to use the attached dll to the previous post I made (click the paperclip).

Frans Bouma | Lead developer LLBLGen Pro
thnk2wn
User
Posts: 31
Joined: 05-Jul-2008
# Posted on: 10-Nov-2008 17:38:54   

Ahh, sorry. The hotfix you provided did remove the exception. However a problem remains in that the BillingCenterId field (from the joined entity) in the ReviewersAndCodersLookup entity appears to be 0 for all records. When I take the query from the output and run it in TOAD, each record in the results has a BillingCenterId value set.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39861
Joined: 17-Aug-2003
# Posted on: 10-Nov-2008 18:06:09   

thnk2wn wrote:

Ahh, sorry. The hotfix you provided did remove the exception. However a problem remains in that the BillingCenterId field (from the joined entity) in the ReviewersAndCodersLookup entity appears to be 0 for all records. When I take the query from the output and run it in TOAD, each record in the results has a BillingCenterId value set.

That's not reproducable with my code (as the CompanyName field is set in my returned data in my unit test).

If you fetch the query in an anonymous type (so refactor the code a bit so you don't fetch it into an EntityCollection), is the field set then? And when you fetch the data without the join? (so straight from the entity)

Btw, the ReviewersAndCodersEntityFactory class... is that also hand-made?

Frans Bouma | Lead developer LLBLGen Pro
thnk2wn
User
Posts: 31
Joined: 05-Jul-2008
# Posted on: 10-Nov-2008 19:54:47   

Yeah the problem appears to be with the execute statement getting the results into an EntityCollection which you are not doing in your sample. If I change the code to the below the BillingCenterId is set:


private EntityCollection<ReviewersAndCodersLookup> FetchReviewersCoders2(IDatabaseAdapter adapter,
            string revCodeType)
        {
            EntityCollection<ReviewersAndCodersLookup> collection = null;
            LinqMetaData metaData = new LinqMetaData(adapter);
            var q = from rc in metaData.ReviewersAndCoders
                 join rcbc in metaData.RevCodeBillingCenters on rc.RevCodeId equals rcbc.RevCodeId
                 where rc.RevCodeFlag == revCodeType
                 orderby rc.Name
                 select new ReviewersAndCodersLookup()
                 {
                     Name = rc.Name,
                     RevCodeId = rc.RevCodeId,
                     RevCodeFlag = rc.RevCodeFlag,
                     BillingCenterId = rcbc.BillingCenterId
                 };         

            foreach (var e in q.Distinct())
            {
                Debug.WriteLine(string.Format("Name = {0}, ", e.Name));
                Debug.WriteLine(string.Format("BillingCenterId = {0}", e.BillingCenterId));
            }

            return collection;
        }

I can workaround for now by walking through and building the entity collection myself but obviously would prefer the execute straight into the entity collection which I would like to work with.

The ReviewersAndCodersEntityFactory class is not hand-made. It is the normal generated code; I just partialed it out just to add a custom method.

thnk2wn
User
Posts: 31
Joined: 05-Jul-2008
# Posted on: 10-Nov-2008 21:32:27   

Ahh, problem solved. The Execute method requires that I serialize and deserialize the custom entity data (BillingCenterId in this case) in the derived entity for the properties that are not a part of the Fields collection. Once I added the below to ReviewersAndCodersLookup it works fine:


        protected override void SerializeOwnedData(SerializationWriter writer, object context)
        {
            base.SerializeOwnedData(writer, context);
            writer.WriteOptimized(_billingCenterId);
        }

        protected override void DeserializeOwnedData(SerializationReader reader, object context)
        {
            base.DeserializeOwnedData(reader, context);
            _billingCenterId = reader.ReadOptimizedInt64();
        }

2 questions left:

1) Is there a reason the entity factory is required for derived and it could not just use default ctors in their absence?

2) Any idea what release the hotfix might go into?

Thanks for the help

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39861
Joined: 17-Aug-2003
# Posted on: 10-Nov-2008 22:01:56   

thnk2wn wrote:

Ahh, problem solved. The Execute method requires that I serialize and deserialize the custom entity data (BillingCenterId in this case) in the derived entity for the properties that are not a part of the Fields collection. Once I added the below to ReviewersAndCodersLookup it works fine:


        protected override void SerializeOwnedData(SerializationWriter writer, object context)
        {
            base.SerializeOwnedData(writer, context);
            writer.WriteOptimized(_billingCenterId);
        }

        protected override void DeserializeOwnedData(SerializationReader reader, object context)
        {
            base.DeserializeOwnedData(reader, context);
            _billingCenterId = reader.ReadOptimizedInt64();
        }

I already thought it would be something outside the scope of the Execute method, as your initial code shouldn't fail with the error you reported in your previous message. simple_smile

2 questions left:

1) Is there a reason the entity factory is required for derived and it could not just use default ctors in their absence?

You need the factory, it's required for creating new instances of the derived type when the data is being fetched.

2) Any idea what release the hotfix might go into? Thanks for the help

In the next public build of v2.6. I guess that will be released this week. You can continue using the build I attached, that's the latest build of the code.

Frans Bouma | Lead developer LLBLGen Pro