This is a migrated thread and some comments may be shown as answers.

How do you use multi-field identity with fields from a base class?

3 Answers 95 Views
General Discussions
This is a migrated thread and some comments may be shown as answers.
This question is locked. New answers and comments are not allowed.
Peter
Top achievements
Rank 1
Peter asked on 25 Nov 2009, 03:05 PM
Hi

I've got a set of classes using a common multi-field identity (and another common field), so I want to use an abstract base class for this.  The relevant documentation says:
    "The corresponding fields of the persistence capable class need not be public, and may also be defined in a persistent base class of this persistent capable class"

I also need horizontal inheritance (completely separate table for each concrete class).  This is also mentioned in the documentation:
    "While using single or multiple field identity, it is required that the horizontally mapped class is declared abstract.

In case of horizontal mapping, the identity and version information is specified at the next derived class, and if the IdentityField and the VersionField specified are fields that belong to the base class, those fields have to be accessible from the derived classes. Therefore, declaring these fields as "Protected" might be the best way, since if these fields are declared as "Private" the enhanced code will not be able to access these fields."

I followed this through but I can only get it to work if the identity fields are defined by the concrete class.  The code is (essentially):

[Persistent]  
public abstract class AuditObject {  
 
    protected int lockVersion;  
    protected int changeSetID;  
 
    protected AuditObject(DomainEntity entity, int changeSetID) {  
        //set base class field values;  
    }  
 
    protected AuditObject() { }  
}  
 
[Persistent(Identity = typeof(Country_Audit.ID))]  
internal class Country_Audit : AuditObject {  
 
    private int entityID;  
 
    internal Country_Audit(Country entity, int changeSetID) : base(entity, changeSetID) {  
        //set concrete class field values  
        }  
 
        internal Country_Audit() { }  
 
        public class ID : IObjectId {  
 
            public int entityID;  
            public int lockVersion;  
 
            public ID() { }  
 
            public ID(string stringRepresentation) {  
                AuditObjectID.Parse(stringRepresentation, out entityID, out lockVersion);  
            }  
 
            //Rest of identity class implementation  
 
        }  
 
    }  
 
 
 
 
 
 

and the corresponding mappings
<class name="AuditObject">  
    <extension key="db-inheritance" value="horizontal"/>  
    <field name="changeSetID">  
        <extension key="db-column">  
            <extension key="db-column-name" value="ChangeSetID" /> 
        </extension> 
    </field> 
    <field name="lockVersion">  
        <extension key="db-column">  
            <extension key="db-column-name" value="LockVersion" /> 
        </extension> 
    </field> 
</class> 
 
<class name="Country_Audit">  
    <extension key="db-table-name" value="Country_Audit" /> 
    <extension key="db-optimistic-locking" value="none"/>  
    <field name="entityID">  
        <extension key="db-column">  
            <extension key="db-column-name" value="CountryID" /> 
        </extension> 
    </field> 
</class> 
 

[The base class - AuditObject - and the concrete class - Country_Audit - are actually in separate assemblies.]

My unit test for this produces an exception:
System.Reflection.TargetInvocationException : Exception has been thrown by the target of an invocation.
  ----> Telerik.OpenAccess.Exceptions.MetadataException : Unable to find primary key field 'lockVersion' for class 'MSW.MAPS.Testbed.Domain.Country_Audit'.

It works fine if I move the lockVersion field into the concrete class (really, I want the entityID field in the base class too; if I do that, I get the equivalent error for that field).

What am I missing? (or is this a bug?)

Best regards, Peter

3 Answers, 1 is accepted

Sort by
0
Accepted
Damyan Bogoev
Telerik team
answered on 26 Nov 2009, 06:09 PM
Hi Peter,

The problem is that the two classes are in different projects. We are aware if it but unfortunately cannot give you an exact time-frame for fixing it.
There are two options that you have - to merge the classes into a single project or to declare the fields from the abstract class in the child class.
Hope that helps.

Kind regards,
Damyan Bogoev
the Telerik team

Instantly find answers to your questions on the new Telerik Support Portal.
Watch a video on how to optimize your support resource searches and check out more tips on the blogs.
0
Peter
Top achievements
Rank 1
answered on 30 Nov 2009, 08:42 AM
Thank you Damyan.

In our case, I wanted to put the base class in a core library used for multiple products; with the limitation you've explaned, we cannot do that, so I'll probably put a copy of the base class into every product (we generate a lot of this code, so that's not a problem for us).

Please do look at removing the restriction in a future release.
Regards, Peter
0
Damyan Bogoev
Telerik team
answered on 30 Nov 2009, 05:59 PM
Hi Peter,

We are currently working on this issue. The restriction will be removed in one of our future releases. We will notify you as soon as any improvements are delivered.
We are sorry for the inconvenience.

Regards,
Damyan Bogoev
the Telerik team

Instantly find answers to your questions on the new Telerik Support Portal.
Watch a video on how to optimize your support resource searches and check out more tips on the blogs.
Tags
General Discussions
Asked by
Peter
Top achievements
Rank 1
Answers by
Damyan Bogoev
Telerik team
Peter
Top achievements
Rank 1
Share this question
or