Casting to Sub-Type Issue

Posts   
 
    
can1
User
Posts: 77
Joined: 16-Sep-2005
# Posted on: 02-Jan-2006 02:22:33   

Hello,

I am having problems using the new inheritance feature in version 2005.1. I am using the adapter pattern with the derived entity templates and VS 2005. I must be making a simple mistake somewhere here.

I have a straight forward hierarchy: SurveyQuestionEntity as the super-type, with SurveyOptionQuestionEntity and SurveyTextQuestionEntity as the sub-types. No discriminator column and using TargetPerEntity structure.

The class definition for the SurveyOptionQuestionEntity show's this:

_public class SurveyOptionQuestionEntity : SurveyQuestionEntity, ISerializable_

The following unit test code results in a compile time failure, reporting "Cannot convert type 'IHHP.Assess.BL.Entities.EntityClasses.DerSurveyQuestionEntity' to 'IHHP.Assess.BL.Entities.EntityClasses.DerSurveyOptionQuestionEntity' "

            _QuestionManager questionManager = new QuestionManager(new OrConfig(_connectionString));

            DerSurveyQuestionEntity question = questionManager.GetSurveyQuestion(10);

            DerSurveyOptionQuestionEntity optionQuestion = (DerSurveyOptionQuestionEntity)question;_

In this case, I know that the question returned (10) is an option type question. I can't figure out why it will not let me cast from the super-type [DerSurveyQuestionEntity] to the sub-type [DerSurveyOptionQuestionEntity], especially at compile time, as I would expect an issue at run-time if I try to cast to the incorrect sub-type. I must be missing something?

Also, using the derived adapter templates, how do I determine at run-time what the type of sub-type is? ie. in this case I know it is an OptionQuestion object, but how do I detect if the sub-type is a TextQuestion object so that I can cast to the appropriate type? I found this thread: http://www.llblgen.com/tinyforum/Messages.aspx?ThreadID=4557&HighLight=1 but it refers to self-servicing templates?

Thanks for your help,

Shawn S

can1
User
Posts: 77
Joined: 16-Sep-2005
# Posted on: 02-Jan-2006 02:45:31   

Der is just my replacement in the derived templates for the original MyObjectEntity references. I tried the same code using the base entity objects, rather than the derived entity objects, and compile time is OK, but the following code fails at run-time with: ""Unable to cast object of type 'IHHP.Assess.BL.Entities.EntityClasses.SurveyQuestionEntity' to type 'IHHP.Assess.BL.Entities.EntityClasses.SurveyOptionQuestionEntity'."

_ QuestionManager questionManager = new QuestionManager(new OrConfig(_connectionString));

SurveyQuestionEntity question = questionManager.GetSurveyQuestion(10);

SurveyOptionQuestionEntity optionQuestion = (SurveyOptionQuestionEntity)question; _

Help. I have double checked the data in the tables and also checked that it does not cast to the other sub-type (which it should not) and all that checks out. What am I doing wrong?

Shawn S

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39619
Joined: 17-Aug-2003
# Posted on: 02-Jan-2006 11:10:37   

can1 wrote:

I am having problems using the new inheritance feature in version 2005.1. I am using the adapter pattern with the derived entity templates and VS 2005. I must be making a simple mistake somewhere here.

I have a straight forward hierarchy: SurveyQuestionEntity as the super-type, with SurveyOptionQuestionEntity and SurveyTextQuestionEntity as the sub-types. No discriminator column and using TargetPerEntity structure.

The class definition for the SurveyOptionQuestionEntity show's this:

_public class SurveyOptionQuestionEntity : SurveyQuestionEntity, ISerializable_

The following unit test code results in a compile time failure, reporting "Cannot convert type 'IHHP.Assess.BL.Entities.EntityClasses.DerSurveyQuestionEntity' to 'IHHP.Assess.BL.Entities.EntityClasses.DerSurveyOptionQuestionEntity' "

            _QuestionManager questionManager = new QuestionManager(new OrConfig(_connectionString));

            DerSurveyQuestionEntity question = questionManager.GetSurveyQuestion(10);

            DerSurveyOptionQuestionEntity optionQuestion = (DerSurveyOptionQuestionEntity)question;_

If you place a breakpoint at the GetSurveyQuestion line, you can check what the type is of question. What is it exactly? Also what's the code in GetSurveyQuestion? If you do this: DerSurveyQuestionEntity toReturn = new DerSurveyQuestionEntity(10); adapter.FetchEntity(toReturn); return toReturn; (not exactly correct code, but you get the point)

you will return an instance of DerSurveyQuestionEntity and not another type. If you want LLBLGen Pro to instantiate the proper type, use FetchNewEntity and pass in the DerSurveyQuestionEntityFactory plus a filter on 10.

Also, using the derived adapter templates, how do I determine at run-time what the type of sub-type is? ie. in this case I know it is an OptionQuestion object, but how do I detect if the sub-type is a TextQuestion object so that I can cast to the appropriate type? I found this thread: http://www.llblgen.com/tinyforum/Messages.aspx?ThreadID=4557&HighLight=1 but it refers to self-servicing templates?

Well, you could of course add your own discriminator column to SurveyQuestion, and manage the value yourself. You can also use 'is' in C# to determine the type at runtime. simple_smile

Frans Bouma | Lead developer LLBLGen Pro
can1
User
Posts: 77
Joined: 16-Sep-2005
# Posted on: 02-Jan-2006 16:32:54   

Frans,

Here are some further details:

Otis wrote:

"If you place a breakpoint at the GetSurveyQuestion line, you can check what the type is of question. What is it exactly?"

If I do a .gettype() after that line executes, it returns:

{Name = "DerSurveyQuestionEntity" FullName = "IHHP.Assess.BL.Entities.EntityClasses.DerSurveyQuestionEntity"}

Otis wrote:

"Also what's the code in GetSurveyQuestion? "


public DerSurveyQuestionEntity GetSurveyQuestion(Int32 questionID)
        {

            try
            {

                using (DataAccessAdapter odapt = new DataAccessAdapter(_OrConfiguration.connectionString))
                {

                    DerSurveyQuestionEntity question = new DerSurveyQuestionEntity(questionID);

                    odapt.FetchEntity(question);
                    
                    return question;

                }
            }

            catch (Exception e)
            {
                Utilities.WriteLog(ref e, "Application");

                throw;
            }

            finally
            {


            }

        }

Otis wrote:

you will return an instance of DerSurveyQuestionEntity and not another type. If you want LLBLGen Pro to instantiate the proper type, use FetchNewEntity and pass in the DerSurveyQuestionEntityFactory plus a filter on 10.

OK. Once I get this basic casting issue worked out, I will look into the FetchNewEntity documentation. I did not realize this, thanks. Also, I will see if the C# is keyword will work for determining the sub-type, if not, I guess I can insert a discriminator column.

Thanks Frans. Let me know if you see anything wrong with the coding Frans. I still can't figure out why I can't cast to the sub-type.

Shawn S.

Otis wrote:

can1 wrote:

I am having problems using the new inheritance feature in version 2005.1. I am using the adapter pattern with the derived entity templates and VS 2005. I must be making a simple mistake somewhere here.

I have a straight forward hierarchy: SurveyQuestionEntity as the super-type, with SurveyOptionQuestionEntity and SurveyTextQuestionEntity as the sub-types. No discriminator column and using TargetPerEntity structure.

The class definition for the SurveyOptionQuestionEntity show's this:

_public class SurveyOptionQuestionEntity : SurveyQuestionEntity, ISerializable_

The following unit test code results in a compile time failure, reporting "Cannot convert type 'IHHP.Assess.BL.Entities.EntityClasses.DerSurveyQuestionEntity' to 'IHHP.Assess.BL.Entities.EntityClasses.DerSurveyOptionQuestionEntity' "

            _QuestionManager questionManager = new QuestionManager(new OrConfig(_connectionString));

            DerSurveyQuestionEntity question = questionManager.GetSurveyQuestion(10);

            DerSurveyOptionQuestionEntity optionQuestion = (DerSurveyOptionQuestionEntity)question;_

If you place a breakpoint at the GetSurveyQuestion line, you can check what the type is of question. What is it exactly? Also what's the code in GetSurveyQuestion? If you do this: DerSurveyQuestionEntity toReturn = new DerSurveyQuestionEntity(10); adapter.FetchEntity(toReturn); return toReturn; (not exactly correct code, but you get the point)

you will return an instance of DerSurveyQuestionEntity and not another type. If you want LLBLGen Pro to instantiate the proper type, use FetchNewEntity and pass in the DerSurveyQuestionEntityFactory plus a filter on 10.

Also, using the derived adapter templates, how do I determine at run-time what the type of sub-type is? ie. in this case I know it is an OptionQuestion object, but how do I detect if the sub-type is a TextQuestion object so that I can cast to the appropriate type? I found this thread: http://www.llblgen.com/tinyforum/Messages.aspx?ThreadID=4557&HighLight=1 but it refers to self-servicing templates?

Well, you could of course add your own discriminator column to SurveyQuestion, and manage the value yourself. You can also use 'is' in C# to determine the type at runtime. simple_smile

Walaa avatar
Walaa
Support Team
Posts: 14951
Joined: 21-Aug-2005
# Posted on: 03-Jan-2006 06:50:45   

Once I get this basic casting issue worked out, I will look into the FetchNewEntity documentation

as Frans said, the FetchNewEntity() will solve your casting issue.

Examine the following example:

if a Worker class inherits from a Person class then:

Worker worker1 = new Worker(); Person aPerson = worker1; // this doesn't require a cast Worker worker2 = (Worker)aPerson; // this requires a cast

This is equivalent to: Person aPerson = new Worker(); Worker worker2 = (Worker)aPerson;

If the object reference aPerson refers to an object of type Person, then the statement Worker worker2 = (Worker)aPerson; will fail

can1
User
Posts: 77
Joined: 16-Sep-2005
# Posted on: 03-Jan-2006 20:14:05   

OK. Thanks. I think I am part-way there. Given the 'FetchNewEntity' method, I got the base casting working on the base entity objects:


using (DataAccessAdapter odapt = new DataAccessAdapter(_OrConfiguration.connectionString))
                {
                    SurveyQuestionEntity question;
                    SurveyOptionQuestionEntity optionQuestion;

                    RelationPredicateBucket bucket = new RelationPredicateBucket();
                    bucket.PredicateExpression.Add(SurveyQuestionFields.QuestionId == questionID);

                    question = (SurveyQuestionEntity)odapt.FetchNewEntity(new SurveyQuestionEntityFactory(), bucket);

                    optionQuestion = (SurveyOptionQuestionEntity)question;

                }

If I try this same methodology on the derived entity objects (I am using the derived templates), it does not work, failing at compile time with "Cannot convert type 'IHHP.Assess.BL.Entities.EntityClasses.DerSurveyQuestionEntity' to 'IHHP.Assess.BL.Entities.EntityClasses.DerSurveyOptionQuestionEntity'":


using (DataAccessAdapter odapt = new DataAccessAdapter(_OrConfiguration.connectionString))
                {
                    DerSurveyQuestionEntity question;
                    DerSurveyOptionQuestionEntity optionQuestion;

                    RelationPredicateBucket bucket = new RelationPredicateBucket();
                    bucket.PredicateExpression.Add(SurveyQuestionFields.QuestionId == questionID);

                    question = (DerSurveyQuestionEntity)odapt.FetchNewEntity(new DerSurveyQuestionEntityFactory(), bucket);

                    optionQuestion = (DerSurveyOptionQuestionEntity)question;

                }

I noticed that the code:


question = odapt.FetchNewEntity(new DerSurveyQuestionEntityFactory(), bucket);

returns a base SurveyOptionEntity object, not the derived object as requested. This seems to be the key in my derived inheritence dilemna. Is there anyway to get it to return the derived entity rather than the base entity type?

Can anyone explain why this is? Can we not used the derived entity templates with the inheritence features? Is this because the derived entities inherit from the base entties, but the derived entities themselves do not participant in any inheritence relationship amongst themselves? Is there a workround?

Thanks for your help. This is my first production project with LLBLGen and I am just trying to work through my learning curve.

Shawn S

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39619
Joined: 17-Aug-2003
# Posted on: 04-Jan-2006 12:37:13   

can1 wrote:

If I try this same methodology on the derived entity objects (I am using the derived templates), it does not work, failing at compile time with "Cannot convert type 'IHHP.Assess.BL.Entities.EntityClasses.DerSurveyQuestionEntity' to 'IHHP.Assess.BL.Entities.EntityClasses.DerSurveyOptionQuestionEntity'":


using (DataAccessAdapter odapt = new DataAccessAdapter(_OrConfiguration.connectionString))
                {
                    DerSurveyQuestionEntity question;
                    DerSurveyOptionQuestionEntity optionQuestion;

                    RelationPredicateBucket bucket = new RelationPredicateBucket();
                    bucket.PredicateExpression.Add(SurveyQuestionFields.QuestionId == questionID);

                    question = (DerSurveyQuestionEntity)odapt.FetchNewEntity(new DerSurveyQuestionEntityFactory(), bucket);

                    optionQuestion = (DerSurveyOptionQuestionEntity)question;

                }

I noticed that the code:

question = odapt.FetchNewEntity(new DerSurveyQuestionEntityFactory(), bucket);

returns a base SurveyOptionEntity object, not the derived object as requested. This seems to be the key in my derived inheritence dilemna. Is there anyway to get it to return the derived entity rather than the base entity type?

Can anyone explain why this is? Can we not used the derived entity templates with the inheritence features? Is this because the derived entities inherit from the base entties, but the derived entities themselves do not participant in any inheritence relationship amongst themselves? Is there a workround?

Thanks for your help. This is my first production project with LLBLGen and I am just trying to work through my learning curve.

I think you're right: DerSurveyOptionQuestionEntity inherits from SurveyOptionQuestionEntity SurveyOptionQuestionEntity doesn't inherit from DerSurveyQuestionEntity but from SurveyQuestionEntity

So casting from DerSurveyQuestionEntity to DerSurveyOptionQuestionEntity isn't possible, as they're not in the same hierarchy...

This is a problem of the derived entity templates. They should contain a modified entityAdapter.template as well... I'll see if I can fix this.

Frans Bouma | Lead developer LLBLGen Pro
can1
User
Posts: 77
Joined: 16-Sep-2005
# Posted on: 04-Jan-2006 14:45:28   

Thanks very much Frans! I will stick with the base entities until a revised derived adapter template is ready. Your help is very much appreciated.

Shawn S

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39619
Joined: 17-Aug-2003
# Posted on: 14-Jan-2006 14:43:44   

I've updated the templates, I hope they'll fix your problem. If you run into other problems with these templates, please let me know simple_smile

Frans Bouma | Lead developer LLBLGen Pro
can1
User
Posts: 77
Joined: 16-Sep-2005
# Posted on: 16-Jan-2006 20:06:22   

I re-generated my classes with the new templates but I am still having a problem, although not at compile time now, just run-time:

The code:

          DerSurveyQuestionEntity question;
                    DerSurveyOptionQuestionEntity optionQuestion;

                    RelationPredicateBucket bucket = new RelationPredicateBucket();
                    bucket.PredicateExpression.Add(SurveyQuestionFields.QuestionId == 16);

            {1}  question = (DerSurveyQuestionEntity)odapt.FetchNewEntity(new DerSurveyQuestionEntityFactory(), bucket);

             {2}       optionQuestion = (DerSurveyOptionQuestionEntity)question;

results in a run-time error on line {2}:

"Unable to cast object of type 'IHHP.Assess.BL.Entities.EntityClasses.SurveyOptionQuestionEntity' to type 'IHHP.Assess.BL.Entities.EntityClasses.DerSurveyOptionQuestionEntity'."

Line {1} results in an object of type SurveyOptionQuestionEntity, not DerSurveyOptionQuestionEntity.

I did re-generate over top of existing class files (as some of them contain custom code now), rather than to a new folder.

Any thoughts?

Can1

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39619
Joined: 17-Aug-2003
# Posted on: 17-Jan-2006 11:21:14   

I think the inheritanceinfoprovider class is the culprit. The problem is that if the data read from the db is of type SurveyOptionQuestionEntity, it will use the factory of SurveyOptionQuestionEntity, not DerSurveyOptionQuestionEntity, as it only knows that factory for that type, not another factory.

I need to alter that template as well and use a custom version of that.

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39619
Joined: 17-Aug-2003
# Posted on: 23-Jan-2006 11:42:36   

I've updated the templates. Please let me know if you have any further issues with the templates. As you can tell by now, I don't have excessive tests on this code, so I don't catch these errors before release.

Frans Bouma | Lead developer LLBLGen Pro