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

4 posts, 1 answers
  1. Peter
    Peter avatar
    23 posts
    Member since:
    Sep 2008

    Posted 25 Nov 2009 Link to this post

    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
  2. Answer
    Damyan Bogoev
    Admin
    Damyan Bogoev avatar
    581 posts

    Posted 26 Nov 2009 Link to this post

    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.
  3. DevCraft banner
  4. Peter
    Peter avatar
    23 posts
    Member since:
    Sep 2008

    Posted 30 Nov 2009 Link to this post

    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
  5. Damyan Bogoev
    Admin
    Damyan Bogoev avatar
    581 posts

    Posted 30 Nov 2009 Link to this post

    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.
Back to Top