Instanciating a subclass using a discriminator value?

Posts   
 
    
Devildog74
User
Posts: 719
Joined: 04-Feb-2004
# Posted on: 21-Oct-2005 04:03:11   

I was poking around in the documentation trying to find a way to create an instance of a sub class entity using a discriminator?

I have an abstract RoleEntity and subclasses for AccountantRoleEntity, CustomerRoleEntity, etc.etc.

Is there a factory generated for this already?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 21-Oct-2005 08:26:29   

That functionality isn't available (for you). AccountantRoleEntity etc. have their own factories, there isn't a method in the RoleEntityFactory which produces entities in the hierarchy based on the discriminator value. This is done to avoid having discriminator values hardcoded in your code, as they might change and if they do, you just have to change them at one place: in the designer.

Internally, there is code which determines what type a set of fields is representing, though that's used by the object fetch code

Frans Bouma | Lead developer LLBLGen Pro
jelling
User
Posts: 22
Joined: 26-Oct-2007
# Posted on: 21-Mar-2008 20:07:14   

Otis wrote:

That functionality isn't available (for you).

Is this still the case? My setup is that I have an abstract class called Evidence and multiple sub-types based on a discriminator column. I get an error when I try this:



        Dim evidenceRecord As EvidenceEntity
        Dim factory As New EvidenceEntityFactory()

        evidenceRecord = factory.CreateEntityFromEntityTypeValue(Me.EvidenceTypeId)

        With evidenceRecord
            .IsNew = False
            .Id = Me.EvidenceId
            .HasCustomSecurity = Me.rblSecurityMode.SelectedValue
            .Save()
        End With


The exception says"Unable to cast object of type 'Project.DAL.EntityClasses.ElementEntity' to type 'Project.DAL.EntityClasses.EvidenceEntity'". It's like the factory is building the wrong type of entity.

Basically, I'm trying to get around having to load a record just to save it polymorphically to save it. This works but requires the object to first be fetched:



        Dim evidenceRecords As New EvidenceCollection
        Dim filter As New PredicateExpression(EvidenceFields.Id = Me.EvidenceId)

        evidenceRecords.GetMulti(filter)

        evidenceRecords(0).HasCustomSecurity = Me.rblSecurityMode.SelectedValue
        evidenceRecords(0).Save()


Thanks,

.jelling

goose avatar
goose
User
Posts: 392
Joined: 06-Aug-2007
# Posted on: 22-Mar-2008 19:37:01   

Are you using inheritance?, if so, could you please provide us with more details about your structure?

jelling
User
Posts: 22
Joined: 26-Oct-2007
# Posted on: 24-Mar-2008 17:49:32   

goose wrote:

Are you using inheritance?, if so, could you please provide us with more details about your structure?

There is table called tblEvidence which is the target for an abstract class called Evidence. From this class, there are multiple inherited classes based on a discriminator column called EvidenceTypeId.

Thanks,

.jelling

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 25-Mar-2008 08:53:05   

CreateEntityFromEntityTypeValue() accepts an entityType value not a descriminator value.

eg. EntityType.CustomerEntity

jelling
User
Posts: 22
Joined: 26-Oct-2007
# Posted on: 25-Mar-2008 16:35:31   

Walaa wrote:

CreateEntityFromEntityTypeValue() accepts an entityType value not a descriminator value.

eg. EntityType.CustomerEntity

Ahh, that explains my weird casting exception.

So is there any way for me to modify a property of the abstract base class without first fetching the record this way?



        Dim evidenceRecords As New EvidenceCollection
        Dim filter As New PredicateExpression(EvidenceFields.Id = Me.EvidenceId)

        evidenceRecords.GetMulti(filter)

        evidenceRecords(0).HasCustomSecurity = Me.rblSecurityMode.SelectedValue
        evidenceRecords(0).Save()


One thought is that I could make the base class non-abstract but I liked having it that way to prevent anyone from creating a generic record.

Thanks,

.jelling

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 26-Mar-2008 10:38:47   

You may try to use UpdateMulti()

jelling
User
Posts: 22
Joined: 26-Oct-2007
# Posted on: 26-Mar-2008 17:29:29   

Walaa wrote:

You may try to use UpdateMulti()

Can you give me an example of how to do this with an abstract base class?

The following fails since there's no constructor - naturally - for the abstract base class.



        'update without loading first
        Dim updatedRecord As New EvidenceEntity
        updatedRecord.HasCustomSecurity = Me.rblSecurityMode.SelectedValue

        evidenceRecords.UpdateMulti(updatedRecord, filter)


Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 27-Mar-2008 12:45:52   

Use the factory of the type simple_smile .

The factory is a workaround to instantiate entities which are marked abstract. That's also why the classes themselves aren't marked abstract, as the framework needs dummy instances to produce query elements.

Frans Bouma | Lead developer LLBLGen Pro
jelling
User
Posts: 22
Joined: 26-Oct-2007
# Posted on: 27-Mar-2008 17:58:25   

Otis wrote:

Use the factory of the type simple_smile .

The factory is a workaround to instantiate entities which are marked abstract. That's also why the classes themselves aren't marked abstract, as the framework needs dummy instances to produce query elements.

...and I'm back where I started. simple_smile

Can you take a look at the code in my initial post and let me know if there's a different way I should be doing this?

Thanks!

.jelling

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 28-Mar-2008 16:53:40   

A factory class should be be generated for an Abstract (marked as Internal) entity class that is a super type in an inheritace hierarchy.

So you can use this factory class to create instances of this entity.

In the generated code, please check: FactoryClasses\EntityFactories.cs

jelling
User
Posts: 22
Joined: 26-Oct-2007
# Posted on: 31-Mar-2008 17:50:15   

Walaa wrote:

A factory class should be be generated for an Abstract (marked as Internal) entity class that is a super type in an inheritace hierarchy.

So you can use this factory class to create instances of this entity.

In the generated code, please check: FactoryClasses\EntityFactories.cs

For anyone else that has this problem, this was the code solution:



        Dim evidenceRecord As EvidenceEntity
        Dim factory As New EvidenceEntityFactory
        evidenceRecord = factory.Create()

        With evidenceRecord
            .IsNew = False
            .Fields(EvidenceFields.Id.Name).ForcedCurrentValueWrite(Me.EvidenceId)
            .HasCustomSecurity = Me.rblSecurityMode.SelectedValue
        End With

        evidenceRecord.Save()