1

How can I change this query expression's join clause so that I don't have to wrap parent.ID in an option just to join on a candidate child.ParentID which might be None?

query { for parent in d.People do
        join child in d.People on (Some parent.ID = child.ParentID)
        exists (child.Birthdate <= parent.Birthdate) }

Thanks!

Jason Kleban
  • 20,024
  • 18
  • 75
  • 125
  • I guess this model is of the lineage of asexual beings – Jason Kleban Sep 19 '14 at 18:27
  • Why is the wrapping a problem? It seems to fit the data well. – Ganesh Sittampalam Sep 19 '14 at 18:43
  • I just want to avoid that extra allocation and constructor, as low-overhead as this situation might be. I wonder if there might be another supported and more efficient syntax that I'm not aware of. – Jason Kleban Sep 19 '14 at 20:49
  • 2
    If this is being translated into SQL and run in the database, why would there be any extra allocations or constructors? – Joel Mueller Sep 19 '14 at 21:21
  • 1
    @uosɐſ if performance is critical, you should not be using linq. – phoog Sep 19 '14 at 21:26
  • it's not about performance as much as it is about understanding whether `join` and similar query syntax clauses are as fully expressive as they could be - and that what seem like limitations by syntax really aren't limitations of expression. In T-SQL, you can have multiple join conditions in a boolean expression tree. In query expressions, you can have multiple keys with tuples (at the cost of an allocation?) but type conversions, inequality, pattern matching I guess not. – Jason Kleban Sep 20 '14 at 12:10
  • And to Joel's comment, it seems like more work to be able to detect the use of `option` and translate it to `... IS NOT NULL AND ...`. Perhaps the loss of resolution there would require a less efficient T-SQL rendering in certain complex queries - or in some *other* situation that evaporates to the same intermediate representation. – Jason Kleban Sep 20 '14 at 12:13
  • I'm not claiming one thing or the other; but that's what I'm wondering about. – Jason Kleban Sep 20 '14 at 12:17

1 Answers1

3

You might like this. There may be a more elegant syntax for this approach, and I expect in the end it is not going to perform much differently, if at all, but here it is:

query { for child in d.People do
        where (child.ParentID.IsSome)
        join parent in d.People on (child.ParentID.Value = parent.ID)
        exists (child.Birthdate <= parent.Birthdate) }

I first came up with this, but I wondered whether it implies calling Value before filtering out the None values:

query { for parent in d.People do
        join child in d.People on (parent.ID = child.ParentID.Value)
        where (child.ParentID.IsSome)
        exists (child.Birthdate <= parent.Birthdate) }

To keep parent first and also put the child filter before the join condition, you can do a subquery, but that seemed a worse solution, not better. If someone knows a way of doing that without the subquery, please add a comment.

phoog
  • 42,068
  • 6
  • 79
  • 117