entityFactoryToUse problem

Posts   
 
    
Nevidion
User
Posts: 17
Joined: 28-Nov-2010
# Posted on: 01-Dec-2010 20:35:16   

I was playing around with the entity factories in one project and have run into a problem, the idea was to create a factory that will set an entity property or even better call a custom entity constructor and set a field value.

Now I have done this using two aproaches, first was to inherit the generated entity factory, add a custom field and constructor and use this to set the entity property, the other is very similar but is achived by modifying the templates so there is no factory inheritance.

Now any of the two aproaches works fine with both EntityCollections and adapter.FetchNewEntity with both a Property being set or calling a custom entity constructor. But it does not work for inherited classes, when I an trying to fetch a child class the entityFactoryToUse is not used, or more correctly it is used just not for the entity I end up with.

I hope this isn't to confusing or abstract but I can post code for any of these if you think it would help. The other relevant information is I use adapter templates, C# code for .NET framework 3.5 and my LLBLGen Pro version is 3.0 (September 8th, 2010).

Might be important but the entities inherit an abstract class, I have not tried it if it's not abstract but I don't see it making a difference here. I am posting here more in search of anwsers then solutions because my problem exists only because i created it simple_smile

Walaa avatar
Walaa
Support Team
Posts: 14993
Joined: 21-Aug-2005
# Posted on: 02-Dec-2010 09:14:01   

Could you please post a simple code snippet?

Nevidion
User
Posts: 17
Joined: 28-Nov-2010
# Posted on: 02-Dec-2010 18:15:58   

Walaa wrote:

Could you please post a simple code snippet?

Ofc, here is the example with the modified templates, add this to the entity factory:

private Int32 _number;

public <[CurrentEntityName]>EntityFactory(Int32 number) : base("<[CurrentEntityName]>Entity", <[RootNamespace]>.EntityType.<[CurrentEntityName]>Entity, <[ If Not IsInHierarchyType None ]>true<[Else]>false<[EndIf]>)
        {
            _number= number;
        }

Modify the existing Create method like this:


        public override IEntity2 Create(IEntityFields2 fields) {
            IEntity2 toReturn = new <[CurrentEntityName]>Entity(fields);
            ((CommonEntityBase)toReturn).Number = _number;<[ UserCodeRegion CurrentEntityName "CreateNew($VALUE)UsingFields" ]>
            // __LLBLGENPRO_USER_CODE_REGION_START <[ UserCodeRegionName ]>
            // __LLBLGENPRO_USER_CODE_REGION_END
            <[ EndUserCodeRegion ]>
            return toReturn;

And then ofc add the property to CommonEntityBase any way you like and use the factory for something like:


AnyEntity entity = adapter.FetchNewEntity(new AnyEntityFactory(5), bucket, prefetchPath) as AnyEntity;

This will work as long as AnyEntity is not in a hierarchy, am I missing something obvious?

Walaa avatar
Walaa
Support Team
Posts: 14993
Joined: 21-Aug-2005
# Posted on: 03-Dec-2010 09:49:39   

AnyEntity entity = adapter.FetchNewEntity(new AnyEntityFactory(5), bucket, prefetchPath) as AnyEntity;

This will work as long as AnyEntity is not in a hierarchy, am I missing something obvious?

Would you please explain in detalis what happens when the entity is in a hierarchy.

Nevidion
User
Posts: 17
Joined: 28-Nov-2010
# Posted on: 03-Dec-2010 10:27:32   

Walaa wrote:

AnyEntity entity = adapter.FetchNewEntity(new AnyEntityFactory(5), bucket, prefetchPath) as AnyEntity;

This will work as long as AnyEntity is not in a hierarchy, am I missing something obvious?

Would you please explain in detail what happens when the entity is in a hierarchy.

Ok, in the above example, entity not in hierarchy -> entity.Number equals 5, if the entity is in a hierarchy entity.Number equals 0, but I guess that's not what you meant.

The instance of AnyEntity that is returned if the entity is in a hierarchy is not the one created by the factory I pass as a parameter. Now the entity instance that is created obviously comes from another instance of the entity factory, either from the EntityFactoryCache which uses the default factory constructor of from the instance created internally by llblgen (entity constructors create a factory instance using the default constructor).

Your question confused me a bit because I am here looking for the exact explanation of what happens.

Walaa avatar
Walaa
Support Team
Posts: 14993
Joined: 21-Aug-2005
# Posted on: 03-Dec-2010 10:52:58   

The instance of AnyEntity that is returned if the entity is in a hierarchy is not the one created by the factory I pass as a parameter. Now the entity instance that is created obviously comes from another instance of the entity factory, either from the EntityFactoryCache which uses the default factory constructor of from the instance created internally by llblgen (entity constructors create a factory instance using the default constructor).

Is the returned instance of the right expected type? If not would you please explain the heirarchy and which type you expected and which was returned.

Does the bucket contain any type filtering?

Nevidion
User
Posts: 17
Joined: 28-Nov-2010
# Posted on: 03-Dec-2010 12:36:40   

Walaa wrote:

Is the returned instance of the right expected type? If not would you please explain the hierarchy and which type you expected and which was returned.

Does the bucket contain any type filtering?

I use a bucket with a predicate expression for the primary key column, in this example the prefetch path does not contain anything. There are no errors, no exceptions, the entity is fetched from the datebase normally, but the Number property is only set if the entity is not in a hierarchy.

I'll try another example, which has the same problem, use all of the above changes to the code and fetch all entities:

EntityCollection<AnyEntity> entityCollection = new EntityCollection<AnyEntity>(new AnyEntityFactory(5));

adapter.FetchEntityCollection(entityCollection);

I hope you got that the Number property is not mapped to a database field, it's just a property added to CommonEntityBase. So everything is fetched normally, all the types are ok, the only difference is the value of the Number property.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39861
Joined: 17-Aug-2003
# Posted on: 06-Dec-2010 10:01:21   

Subtypes are created using their own factories. So if you define a new SuperTypeFactory(), the subtypes are created using their own factories, not SuperTypeFactory. This also means that SuperTypeFactory() code isn't called. The reason is that you can instantiate a class only once, so you call the subtype to instantiate the class, not the subtype AND the supertype's factory.

to init properties, you can also use a partial class and override OnInitialized()

Frans Bouma | Lead developer LLBLGen Pro
Nevidion
User
Posts: 17
Joined: 28-Nov-2010
# Posted on: 06-Dec-2010 12:42:59   

Otis wrote:

Subtypes are created using their own factories. So if you define a new SuperTypeFactory(), the subtypes are created using their own factories, not SuperTypeFactory. This also means that SuperTypeFactory() code isn't called. The reason is that you can instantiate a class only once, so you call the subtype to instantiate the class, not the subtype AND the supertype's factory.

to init properties, you can also use a partial class and override OnInitialized()

I know that, but in the above example the factory is the SubTypeFactory, I'll try and setup an example project this evening.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39861
Joined: 17-Aug-2003
# Posted on: 07-Dec-2010 09:24:28   

I didn't get that from the posts you made in this thread.

Anyway, the thing is that you should pass in the factory for the supertype, that one is used to obtain fields for the query, and then based on the row data, the proper factory is produced and is used to create the subtype instance.

I think in this mechanism is the reason why you don't see your factory used: in the InheritanceInfoProvider.cs class (generated in the helper classes folder/namespace), the factory per type is specified. It's this factory that's returned to the o/r core to use for the type, not yours.

You can intercept this in your supertype's factory, by overriding 'GetEntityFactory' and first call the base' method. If it returns the type you want to override, return an instance of the factory you want to use instead.

Frans Bouma | Lead developer LLBLGen Pro
Nevidion
User
Posts: 17
Joined: 28-Nov-2010
# Posted on: 07-Dec-2010 22:26:56   

Otis wrote:

I didn't get that from the posts you made in this thread.

Anyway, the thing is that you should pass in the factory for the supertype, that one is used to obtain fields for the query, and then based on the row data, the proper factory is produced and is used to create the subtype instance.

I think in this mechanism is the reason why you don't see your factory used: in the InheritanceInfoProvider.cs class (generated in the helper classes folder/namespace), the factory per type is specified. It's this factory that's returned to the o/r core to use for the type, not yours.

You can intercept this in your supertype's factory, by overriding 'GetEntityFactory' and first call the base' method. If it returns the type you want to override, return an instance of the factory you want to use instead.

Thanks that was the information I was missing, I still use the subtype factory but I changed the GetEntityFactory method for EntityFactoryBase2 from

        public override IEntityFactory2 GetEntityFactory(object[] fieldValues, Dictionary<string, int> entityFieldStartIndexesPerEntity) 
        {
            IEntityFactory2 toReturn = (IEntityFactory2)InheritanceInfoProviderSingleton.GetInstance().GetEntityFactory(this.ForEntityName, fieldValues, entityFieldStartIndexesPerEntity);
            if(toReturn == null)
            {
                toReturn = this;
            }
            return toReturn;
        }

to

        public override IEntityFactory2 GetEntityFactory(object[] fieldValues, Dictionary<string, int> entityFieldStartIndexesPerEntity) 
        {
            IEntityFactory2 toReturn = (IEntityFactory2)InheritanceInfoProviderSingleton.GetInstance().GetEntityFactory(this.ForEntityName, fieldValues, entityFieldStartIndexesPerEntity);
            if(toReturn == null || this.GetType() == toReturn.GetType())
            {
                toReturn = this;
            }
            return toReturn;
        }

Hope I didn't break anything, but even if I did I'll handle it when I get there, thanks for the help!