4

I have a fairly unique situation, I have never needed to this before anyways. I have a Linq query that returns data from a database using EF4.1. I want to create multiple similar (same signature) anonymous (or even named if necessary) results from each query result.

Here's the code i'm using now:

var data = getMyData().Select(x => 
              new 
              {
                GoalName = x.GoalType.Name, 
                Start = x.StartDate, 
                End = x.EndDate, 
                x.StartValue, 
                x.CheckIns
              }).ToList();

var r1 = data.Select(x => 
              new 
              { 
                title = x.GoalName, 
                start = x.Start.ToString(), 
                end = x.End.ToString(), 
                className = "hidden", 
                type = "goal"
              });

var r2 = data.Select(x => 
              new 
              { 
                title = string.Format("Start: {0:0.##}", x.StartValue), 
                start = x.Start.ToString(), 
                end = x.Start.ToString(), 
                className = "", 
                type = "" 
              });

var r3 = data.Select(x => 
              new 
              { 
                title = "End", 
                start = x.End.ToString(), 
                end = x.End.ToString(), 
                className = "", 
                type = "" 
              });

var r4 = data.SelectMany(x => x.CheckIns)
           .Select(y => 
              new 
              { 
                title = y.CheckInValue.Value.ToString(), 
                start = y.CheckInDateTime.ToString(), 
                end = y.CheckInDateTime.ToString(), 
                className = "", 
                type = "" 
              });

var result = r1.Union(r2).Union(r3).Union(r4);

Now maybe this is as good a way as any, but I can't help feeling that i'm missing something.

Is there a better solution?

8
  • You might want to reformat the code to be easier to read for those willing to help you. Commented Sep 7, 2011 at 3:25
  • Also, could you clarify what you are trying to get returned? Commented Sep 7, 2011 at 3:27
  • @Chris Pietschmann - the code already was formatted, it just didn't have spaces between lines. I guess that's a personal preference. In any event, it's pretty obvious from looking at the code what I get back, and the code works fine. I'm just looking for something that does exactly the same thing, but more efficient. Commented Sep 7, 2011 at 4:15
  • 2
    Why are you using Union instead of Concat? It looks like you want to simply concatenate these not calculate the set union of them (which involves comparing them against each other for equality), right? Commented Sep 7, 2011 at 5:20
  • 1
    My point on the ToString() was that you don't need to do it in so many places: you can either do it in the first Select, or you can add a another Select at the end that does it. Commented Sep 8, 2011 at 23:03

3 Answers 3

3

What you have is actually OK I think.

But StevenzNPaul's suggestion not that bad, here's how you can use the let keyword to store the different projections, then select the results individually (for brevity, I did not project all the fields, but you get the point):

var query = from x in data
            let result1 = new {title = x.GoalName, start = x.Start}
            let result2 = new {title = string.Format("Start: {0:0.##}", x.StartValue), start = x.Start}
            let result3 = new {title = "End", start = x.End}
            let checkins = x.CheckIns.Select(checkin => new { title = "...", start = checkin.Start })
            from result in new[] { result1, result2, result3 }.Concat(checkins)
            select result;

Obviously, whether this is better is a matter of preference. Also, this will result in a different ordering, which may or may not be a problem for you.

Sign up to request clarification or add additional context in comments.

2 Comments

I stand corrected. I see what you mean. This code looks like it would likely result in several extra objects being created as well as more Selects. In any case, an interesting solution.
I don't think it creates more objects. The main difference is that with this solution you loop over the input list (data) only once. The extra Selects just add more weight to 'the body of the for loop'.
3

You can create an iterator using yield which also has the advantage of being evaluated lazily (doesn't require the ToList()). I created a typed class Result to hold the query results

private IEnumerable<Result> PerformQuery()
{
    var results= getMyData().Select(x => new {GoalName = x.GoalType.Name, 
   Start = x.StartDate, End = x.EndDate, x.StartValue, x.CheckIns});

    foreach (var result in results)
    {
          yield return new Result() { Title = result.GoalName, Start = result.Start.ToString(), End = result.End.ToString(), ClassName = "Hidden", Type = "Goal" };

          yield return new Result() { Title = String.Format("Start: {0:0.##}",result.StartValue), Start = result.Start.ToString(), End = result.Start.ToString() }

          yield return new Result() { Title = "End", Start = result.End.ToString(), End = result.End.ToString() };

          foreach (var checkIn in result.CheckIns)
               yield return new Result() { Title = checkIn.CheckInValue.Value.ToString(), Start = checkIn.CheckInDateTime.ToString(), End = checkIn.CheckInDateTime.ToString() };
    }
}

1 Comment

An interesting approach, but seems less to add an additional layer of abstraction and thus slightly slower.
1

try using let keyword it will work for you.

1 Comment

Let does not do what I need. Let allows you to use several queries to make one query. I want the reverse, one query with several result sets projected back into a single result.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.