Horizontal inheritance with default mapping not working

6 posts, 0 answers
  1. Joseph Lam
    Joseph Lam avatar
    10 posts
    Member since:
    Jan 2010

    Posted 21 Jul 2014 Link to this post

    My model looks like this:

    public abstract class EntityBase
    {
        public int ID { get; set; } // intended to be the identity for each concrete class
    }

    public class MyEntity: EntityBase
    {
        public string SomeField { get; set; }
    }

    My mapping code:

    var entityBaseMapping = new MappingConfiguration<EntityBase>();
    entityBaseMapping.MapType().Inheritance(InheritanceStrategy.Horizontal);

    var myEntityMapping = new MappingConfiguration<MyEntity>();
    myEntityMapping.MapType();
    myEntityMapping.HasProperty(x => x.ID).IsIdentity();

    Get this error when compiling:

    Error 1 Type 'MyEntity' cannot access private identity field '<ID>k__BackingField' declared by type 'EntityBase'. The declaring type enhances this field as non-identity field.  Make sure to use a consistent mapping for both types or declare the field as protected.  Alternatively consider moving the identity field to the derived class. (OpenAccessEnhancedCopyKeyFieldsFromObjectId) 





  2. Kaloyan Nikolov
    Admin
    Kaloyan Nikolov avatar
    118 posts

    Posted 24 Jul 2014 Link to this post

    Hi Joseph,

    The reason is that the Telerik Data Access Enhancer tool is trying to access the filed of the ID property when processing the derived class. As the auto property generates a private filed it is not accessible from the derived class context. To solve this issue use a full property where the backing field is protected, like this:
    public abstract class EntityBase
    {
        protected int iD;
        public int ID
        {
            get
            {
                return this.iD;
            }
            set
            {
                this.iD = value;
            }
        } // intended to be the identity for each concrete class
    }


    I hope this helps. Should you have any additional questions do not hesitate to get back.

    Regards,
    Kaloyan Nikolov
    Telerik
     
    OpenAccess ORM is now Telerik Data Access. For more information on the new names, please, check out the Telerik Product Map.
     
  3. DevCraft banner
  4. Joseph Lam
    Joseph Lam avatar
    10 posts
    Member since:
    Jan 2010

    Posted 24 Jul 2014 in reply to Kaloyan Nikolov Link to this post

    Thanks. I think the example in the documentation missed this point:
    http://docs.telerik.com/data-access/developers-guide/code-only-mapping/inheritance/fluent-mapping-inheritance-default-mapping

    In the C# Animal class it should have used a protected backing field.
  5. Joseph Lam
    Joseph Lam avatar
    10 posts
    Member since:
    Jan 2010

    Posted 25 Jul 2014 in reply to Kaloyan Nikolov Link to this post

    Is there a way to configure the identity column once for the abstract base class so I don't have to repeat "myEntityMapping.HasProperty(x => x.ID).IsIdentity();" for all my entities?
  6. Doroteya
    Admin
    Doroteya avatar
    502 posts

    Posted 28 Jul 2014 Link to this post

    Hi Joseph,

    Kindly find the answers you inquiries as follows:

    1. Configuring the identity property in Horizontal inheritance
    The general idea behind the horizontal inheritance structures is that the base class does not have a representation inside the database. With this in mind, and in order for the proper runtime behavior of Telerik Data Access, it is important that each of the child classes has its own configuration for the identity property regardless of the fact that in the conceptual model, it belongs to the base class.

    2. Usage of protected backing fields in the documentation examples
    Indeed, the example demonstrated in the mentioned article does not provide you with the implementation of the Animal class. I added a task for an update of the documentation with the relevant information, but at the time present I cannot provide you with a timeframe for it.

    I hope this helps. If you need further information, do not hesitate to get back to us.



    Regards,
    Doroteya
    Telerik
     
    OpenAccess ORM is now Telerik Data Access. For more information on the new names, please, check out the Telerik Product Map.
     
  7. Andrey
    Andrey avatar
    1 posts
    Member since:
    May 2014

    Posted 19 Jan Link to this post

    This can be achieved without the use of inheritance

    public partial class ModelMetadata : FluentMetadataSource
    {
        protected override IList<MappingConfiguration> PrepareMapping()
        {
            List<MappingConfiguration> mappingConfigurations = new List<MappingConfiguration>();
     
            mappingConfigurations.Add(CreateBaseConfiguration<Positions>());
            mappingConfigurations.Add(CreateBaseConfiguration<Departament>());
      
            return mappingConfigurations;
        }
    }
        

    private MappingConfiguration<T> CreateBaseConfiguration<T>() where T : IPortalDataBase
    {
        MappingConfiguration<T> baseConfig = new MappingConfiguration<T>();
        baseConfig.MapType().WithConcurencyControl(OptimisticConcurrencyControlStrategy.Version).UseDefaultMap();
        baseConfig.HasProperty(c => c.Id).IsIdentity(KeyGenerator.Guid).IsNotNullable();
        baseConfig.HasProperty(c => c.Timestamp).IsVersion();
        baseConfig.HasProperty(c => c.Create).IsCalculatedOn(DateTimeAutosetMode.Insert);
        baseConfig.HasProperty(c => c.Update).IsCalculatedOn(DateTimeAutosetMode.InsertAndUpdate);
        baseConfig.HasProperty(c => c.Status).HasDefaultValue();
        return baseConfig;
    }

    use interface

    public interface IPortalDataBase
    {
        Guid Id { get; set; }
        DateTime Create { get; set; }
        DateTime Update { get; set; }
        Int64 Timestamp { get; set; }
        DataStatus Status { get; set; }
    }

    The main drawback - the interface implementation. But it can just copy (or use the T4). But changing the interface implementation (a rare problem) and the class CreateBaseConfiguration we get a list of errors implementation of the interface in the other classes. Which just decide copying.

    public class Departament : IPortalDataBase
    {
        public Guid Id { get; set; }
        public DateTime Create { get; set; }
        public DateTime Update { get; set; }
        public Int64 Timestamp { get; set; }
        public DataStatus Status { get; set; }
     
        public string Name { get; set; }
    }
     Too bad that you can not do the same properties in all classes automatically. Since the identifiers are usually the same, it is often used basic functions, such as versioning.It lacks some features, for example, instead of removing only marked as deleted, to preserve the history. But it is possible to realize the most hands.

Back to Top
DevCraft banner