In Derived Model, can't denormalize a field that comes from an inherited class

Posts   
 
    
Posts: 98
Joined: 10-Nov-2006
# Posted on: 27-Feb-2017 20:21:55   

LLBLGen version 5.1.3 Adapter Platform: .NET 4.6.1 Language: C# Framework: DTO Class Model Preset: SD.DTOClasses.ReadOnlyDTOs SQL Server

This is a continuation of the discussion here: http://llblgen.com/TinyForum/Messages.aspx?ThreadID=24188

Just as in that case, I have a entity model with this structure:

Client (ClientId int PK, Name varchar(10)) Project (ProjectId int PK, Name varchar(10), ClientId int FK) Event(EventId int PK FK) (Event is a subclass of Project with the TargetPerEntity approach, so Event.EventId = Project.ProjectId) MealType (MealTypeId int PK, Name varchar(10), EventId int FK)

In other words, a MealType has 1 related Event, Event is a subclass of Project, and a Project has a 1 related Client.

Just as in that previous thread, I'm creating a Derived Model based on MealType. In the "Derived Element Sub-Element Selection" panel, I see the attributes of MealType, as expected. Under MealType, there is an "Event" subtree, as expected. In that subtree, there are all the fields from both Event and also from Project, which is as expected (since Project is the base class of Event). Also under the "Event" subtree are sub-subtrees for all the entities that are related to Event, and (now) all the relations from "Project" .

Under the "Event" subtree I want to include the "Name" field (which actually comes from "Project"), and so I select that. If I generate, compile, and run the code, then it all works as expected.

But, I want to denormalize that "Name" field and include it directly in the "MealType" entity. However, the designer won't allow denormalizing that field.

In the previous thread, you said this would be the case:

Denormalization is limited in this case regardless, as you can't denormalize an inherited field, but that's logical.

But, I don't see why denormalization is not allowed in this case. As an experiment, I took the generated DTO, that looked like this:

namespace GreaterGiving.Data.Audit.DtoClasses
{
    /// <summary> DTO class which is derived from the entity 'MealType'.</summary>
    public partial class MealTypeAudit
    {
        /// <summary>Gets or sets the Event field. </summary>
        public MealTypeAuditTypes.EventEvent Event { get; set; }

        /// <summary>Gets or sets the MealTypeId field. Derived from Entity Model Field 'MealType.MealTypeId'</summary>
        public System.Int32 MealTypeId { get; set; }

        /// <summary>Gets or sets the Name field. Derived from Entity Model Field 'MealType.Name'</summary>
        public System.String Name { get; set; }
    }

    namespace MealTypeAuditTypes
    {
        /// <summary> DTO class which is derived from the entity 'Event (Event)'.</summary>
        public partial class EventEvent
        {
            /// <summary>Gets or sets the ClientClientId field. Derived from Entity Model Field 'Client.ClientId (Event.Client)'</summary>
            public System.Int32 ClientId { get; set; }

            /// <summary>Gets or sets the ClientName field. Derived from Entity Model Field 'Client.Name (Event.Client)'</summary>
            public System.String ClientName { get; set; }

            /// <summary>Gets or sets the Name field. Derived from Entity Model Field 'Project.Name'</summary>
            public System.String ProjectName { get; set; }

            /// <summary>Gets or sets the ProjectId field. Derived from Entity Model Field 'Project.ProjectId'</summary>
            public System.Int32 ProjectId { get; set; }
        }
    }

}

And changed it to this by getting rid of the embedded class and moving all fields to the top level:

namespace GreaterGiving.Data.Audit.DtoClasses
{
    /// <summary> DTO class which is derived from the entity 'MealType'.</summary>
    public partial class MealTypeAudit2
    {
        /// <summary>Gets or sets the Event field. </summary>
        public System.Int32 MealTypeId { get; set; }

        /// <summary>Gets or sets the Name field. Derived from Entity Model Field 'MealType.Name'</summary>
        public System.String Name { get; set; }

        /// <summary>Gets or sets the ClientClientId field. Derived from Entity Model Field 'Client.ClientId (Event.Client)'</summary>
        public System.Int32 ClientId { get; set; }

        /// <summary>Gets or sets the ClientName field. Derived from Entity Model Field 'Client.Name (Event.Client)'</summary>
        public System.String ClientName { get; set; }

        /// <summary>Gets or sets the Name field. Derived from Entity Model Field 'Project.Name'</summary>
        public System.String ProjectName { get; set; }

        /// <summary>Gets or sets the ProjectId field. Derived from Entity Model Field 'Project.ProjectId'</summary>
        public System.Int32 ProjectId { get; set; }
    }
}

I made matching changes in the Persistence class, changing from:

private static System.Linq.Expressions.Expression<Func<GreaterGiving.Data.AdapterData.EntityClasses.MealTypeEntity, GreaterGiving.Data.Audit.DtoClasses.MealTypeAudit>> CreateProjectionFunc()
        {
            return p__0 => new GreaterGiving.Data.Audit.DtoClasses.MealTypeAudit()
            {
                Event = new GreaterGiving.Data.Audit.DtoClasses.MealTypeAuditTypes.EventEvent()
                {
                    ClientId = p__0.Event.Client.ClientId,
                    ClientName = p__0.Event.Client.Name,
                    ProjectName = p__0.Event.Name,
                    ProjectId = p__0.Event.ProjectId,
                },
                MealTypeId = p__0.MealTypeId,
                Name = p__0.Name,
            };
        }

to this:

private static System.Linq.Expressions.Expression<Func<GreaterGiving.Data.AdapterData.EntityClasses.MealTypeEntity, GreaterGiving.Data.Audit.DtoClasses.MealTypeAudit2>> CreateProjectionFunc()
        {
            return p__0 => new GreaterGiving.Data.Audit.DtoClasses.MealTypeAudit2()
            {
                ClientId = p__0.Event.Client.ClientId,
                ClientName = p__0.Event.Client.Name,
                ProjectName = p__0.Event.Name,
                ProjectId = p__0.Event.ProjectId,
                MealTypeId = p__0.MealTypeId,
                Name = p__0.Name,
            };
        }

This change works fine. The code compiles fine and fetches the correct data.

So, why is the designer enforcing this restriction that (at least in my case) seems to not be necessary?

Thanks,

Wesley

Attachments
Filename File size Added on Approval
Denormalize.png 73,349 27-Feb-2017 20:24.26 Approved
Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 28-Feb-2017 03:31:36   

Reproduced.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39613
Joined: 17-Aug-2003
# Posted on: 28-Feb-2017 11:30:51   

Yes you're correct. I misread the design docs

No fields of docs in Set of subtypes can move to parent doc If the Embedded Document is a single element document, fields from the root doc can be moved to the parent doc. Fields of documents in the Set of subtypes however aren't possible to move to the parent doc, as it's not said all elements in the set of instances of the Embedded Document are of that type at runtime. Example: Boardmember.CompanyCar: a field from CompanyCar can be moved to Boardmember however a field from FamilyCar, a subtype of CompanyCar, can't, as the CompanyCar might be of type SportsCar at runtime.

Here your fields should be denormalizable. A restriction which is now visible due to the change in the visibility of navigators we made last week. Will make the changes.

The code used is the same as for the subtype derived elements, which shouldn't allow denormalization as the element can be of another subtype, however inherited fields over a direct relationship aren't the same, so the code has to make that distinction.

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39613
Joined: 17-Aug-2003
# Posted on: 28-Feb-2017 16:41:22   

Implemented in v5.0.10 and v5.1.3 hotfix builds, now available.

Thanks for reporting this and the previous issues, made the Derived Models more usable simple_smile

Frans Bouma | Lead developer LLBLGen Pro