QuerySpec + WithProjector

Posts   
 
    
Isz
User
Posts: 108
Joined: 26-Jan-2006
# Posted on: 17-May-2012 21:36:03   

Hello,

More fun with QuerySpec...

In my LLBLGen project I am using inheritance (Target-per-Entity-Hierarchy I think), and some custom templates that create POCO-like objects I project records on to. My templates actually carry over the inheritance too, but I wasn't really able to leverage it using LINQ, but it looks like I can using QuerySpec + WithProjector?

I am wondering how this could best be achieved, rather than the less desirable approach I just brainstormed below.

Here's some example code:

Base


    public partial class SourceAdvisoryMetaData : IMetaData
    {   
        [Key]
        public virtual System.Int32 SourceAdvisoryId { get; set; }
        public virtual System.String Description { get; set; }
        public virtual System.String Title { get; set; }
        
        //  Mapped fields on related field.
    }

Subtype


    public partial class SourceAdvisoryFooMetaData : SourceAdvisoryMetaData, IMetaData
    {   
        public virtual System.DateTime AdvisoryDate { get; set; }
        public virtual System.String Criticality { get; set; }
...
    }

So with QuerySpec, I am thinking since I have to use a DynamicQuery, I select all my fields first, then use WithProjector, and based upon some value existing in the selection criteria I would be able to return the type of object it is, either a base (SourceAdvisoryMetaData) or a child (SourceAdvisoryFooMetaData).

But that doesn't seem ideal.

Query


            var q = qf.SourceAdvisory
                .Select(() => new 
                {
                     // Base
                    SourceAdvisoryId = SourceAdvisoryFields.SourceAdvisoryId.ToValue<int>(),
                    Title = SourceAdvisoryFields.Title.ToValue<string>(),
                    Description = SourceAdvisoryFields.Description.ToValue<string>(),

                    // ...

                    // Child
                    AdvisoryDate  = SourceAdvisoryFooFields.AdvisoryDate.ToValue<DateTime?>(),
                    Criticality = SourceAdvisoryFooFields.Criticality .ToValue<string>(),
                }
                )
                .WithProjector(t => 
                    {
                        //  It's a subtype
                        if (t[12] != null)
                        {
                            return new SourceAdvisoryFooMetaData { };
                        }

                        //  It's a basetype
                        return new SourceAdvisoryMetaData { };

                    }
                )
                ;



How might the actual type be accessed in a DynamicQuery so I can create the correct projected POCO type (probably a cake-and-eat-it-too kind of question)?

Thanks!

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 18-May-2012 11:36:06   

IMHO this can be acceptable, since you are fetching a flat (dynamic) list.

Isz
User
Posts: 108
Joined: 26-Jan-2006
# Posted on: 18-May-2012 17:39:18   

OK, what I did was in the select clause, capture the child table's primary key (which is also the FK mapping to the parent), but I found I had to alias this so I wouldn't get the error "Key has already been added..."



            var q = qf.SourceAdvisory
                .Select(() => new
                {
                     // Base
                    SourceAdvisoryId = SourceAdvisoryFields.SourceAdvisoryId.ToValue<int>(),
                    Title = SourceAdvisoryFields.Title.ToValue<string>(),
                    Description = SourceAdvisoryFields.Description.ToValue<string>(),

                    // ...

                    // Child
                    SourceAdvisoryFooId = SourceAdvisoryFooFields.SourceAdvisoryId.As("SourceAdvisoryFooId").ToValue<int>(),
                    AdvisoryDate = SourceAdvisoryFooFields.AdvisoryDate.ToValue<DateTime?>(),
                    Criticality = SourceAdvisoryFooFields.Criticality .ToValue<string>(),
                }
                )
                .WithProjector(t =>
                    {
                         SourceAdvisoryMetaData s = new SourceAdvisoryMetaData { };

                        // It's a subtype
                        if (t.Get<int>("SourceAdvisoryFooId") > 0)
                        {
                            s = new SourceAdvisoryFooMetaData
                            {
                                SourceAdvisoryId = t["SourceAdvisoryFooId"].ToNullable<int>() ?? 0,
                                AdvisoryDate = t["AdvisoryDate"].ToNullable<DateTime>() ?? DateTime.MinValue,
                                AdvisoryId = t["AdvisoryId"].ToNullable<int>() ?? 0,
                            };
                        }

                        //  Common base type fields
                        s.SourceAdvisoryId = t["SourceAdvisoryId"].ToNullable<int>() ?? 0;
                        s.Title = t["Title"] as string;

                           return s;

                    }
                )
                ;

Another part of the query I am having a problem with setting an alias, but I'll start another thread for that.

Thanks for the feedback!

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 18-May-2012 21:58:17   

Isz wrote:

OK, what I did was in the select clause, capture the child table's primary key (which is also the FK mapping to the parent), but I found I had to alias this so I wouldn't get the error "Key has already been added..."

That code is ok. And yes, if you will use WithProjector you should be careful with those custom alias.

Isz wrote:

Another part of the query I am having a problem with setting an alias, but I'll start another thread for that.

Ok wink

David Elizondo | LLBLGen Support Team