Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

309
Views
LINQPad: How do I add a property to each row being dumped?

In LINQPad, I frequently want to Dump some SQL table, but add a property to each row. I usually default to the simple:

Publishers
.Select(p => new { p, AppCount = p.Apps.Count() })

But of course this results in messy output, because each item is formatted as a vertical table, with an extra column containing the added property. I could create a new object, but that's very verbose, and you lose the table traversal links:

Publishers
.Select(p => new { p.PublisherId, p.Name, p.Added, ..., AppCount = p.Apps.Count() })

What I'd love is some sort of merge syntax, which creates a dynamic object to dump with the added property:

Publishers
.Select(p => p.Merge(new { AppCount = p.Apps.Count() })

I've tried a few different ways to accomplish that: using JsonConvert.SerializeObject (this goes haywire trying to serialize all the foreign key references and repeating loops, using ExpandoObject (couldn't come up with a nice clean syntax), and libraries like https://github.com/kfinley/TypeMerger, which I haven't gotten to work either.

Has anyone come up with a clean way to do this? Does LINQPad have some built in synax for this I can use? Thanks!

UPDATE: I uploaded a sample script to demonstrate the issue and let anyone try their solutions against: http://share.linqpad.net/kclxpl.linq

To run, you'll need to populate the Nutshell database, which you can do using the "Populate demo database" sample in LINQPad.

over 4 years ago · Santiago Trujillo
3 answers
Answer question

0

You can add some extension methods to make this work. I do not recommend adding these to My Extensions because they require importing System.Dynamic which you probably don't want for most queries. Put these in another query which imports System.Dynamic and #load it when desired.

public static class ExpandoObjectExt {
    // convert object to ExpandoObject, add a property and return as dynamic
    public static dynamic With<T, TAdd>(this T obj, string propName, TAdd val) {
        var eo = Util.ToExpando(obj);
        var objDict = (IDictionary<string, object>)eo;
        objDict[propName] = val;
        return eo;
    }
    // convert IEnumerable<T> to IEnumerable<dynamic>, adding a property to each object
    public static IEnumerable<dynamic> With<T, TAdd>(this IEnumerable<T> src, string propName, Func<T, TAdd> valFn) => src.Select(s => s.With(propName, valFn(s)));
}

Now you can use this like:

Publishers
    .With("AppCount", p => p.Apps.Count())

However, conversion to ExpandoObject will eliminate any hyperlinks for collection properties, you can get around this by specifying only one level of output with an explicit .Dump(1). You could also write a custom Util.ToExpando (the code is here) that uses Util.OnDemand to create hyperlinks for collection properties.

Also, if you want to add more than one property, you can write variations of With that take multiple pairs or a version that tests for an ExpandoObject (and IEnumerable<ExpandoObject>) and can be chained fluent style.

over 4 years ago · Santiago Trujillo Report

0

I've got a slight variation on NetMage's extension method. Try this instead:

public static object Extendo(this object @object, Action<dynamic> inject)
{
    dynamic e = Util.ToExpando(@object);
    inject(e);
    return (object)e;
}

The Action<dynamic> allows this code to be written:

var people = new[]
{
    new { name = "Fred", age = 41 },
    new { name = "John", age = 67 },
    new { name = "Dave", age = 23 },
};

people
    .Select(p => p.Extendo(d => d.IsOld = p.age >= 55))
    .Dump();

first

I can extend this slightly again with this method:

public static object Extendo<T>(this IEnumerable<T> source, Action<T, dynamic> inject) =>
    source.Select(x => x.Extendo(d => inject(x, d)));

Now I can write this:

people.Extendo((p, d) => d.IsOld = p.age >= 55).Dump();

I get the same result.

Of course, these methods effectively return object so there's no further computation that can be done. So it's probably worthwhile just going straight for Dump. Try this:

public static void Dump<T>(this IEnumerable<T> source, Action<T, dynamic> inject) =>
    source.Select(x => x.Extendo(d => inject(x, d))).Dump();

Now you just write this:

people.Dump((p, d) => d.IsOld = p.age >= 55);
over 4 years ago · Santiago Trujillo Report

0

This is a tricky problem to solve. Part of the problem is that the metadata that allows LINQPad to identity lazily loaded properties is lost when they're taken out of their "entity" home and moved to an ExpandoObject, causing excessive round-tripping.

To avoid the pain, I've added a Util.Merge method to LINQPad 7.2.7. Here's its simplest use:

var o1 = new { A = 1, B = 2 };
var o2 = new { C = 3, D = 4 };

Util.Merge (o1, o2).Dump();

and for the problem at hand:

Publishers
   .Select(p => Util.Merge (p, new { AppCount = p.Apps.Count() }))
over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!