1

I have a requirement to produce an "flattened" version of data for export, in which the customer wants the related table rows to appear as columns. We're using Entity Framework 4 & .NET 4.0

The customer has the ability to create custom questions for their events. There may be zero to infinite questions. Users attending the event may answer none, some or all of those questions.

partial entity diagram

What I need to produce is like this:

User 1    User 1 info field A   User 1 info field B    User 1 Answer to question A    User 1 Answer to Question B
User 2    User 2 info field A   User 2 info field B    User 2 Answer to question A    User 2 Answer to Question B

Creating the user info portion of the result set is not problem, but I'm stumped on how to take my related questions and answers, i.e.:

from urf in tblUserRegistrationFields.Include("tblRegistrationFields")
where urf.UserID == eachUserID && urf.tblRegistrationField.EventID == thisEventID
select new
{
    FieldLabel = urf.tblRegistrationField.FieldLabel, //this is the question name
    value = urf.value //this is the user's answer
}

And add those to my user select statement as individual columns, i.e.:

var users = from u in context.tblUsers
            <snip>
            select new
            {
                UserID = u.UserID,
                <snip>,
                CustomQuestionA = AnswerA,
                CustomQuestionB = AnswerB,
                ... etc.
            };

Ultimately I need to create a grid which I can then export to their desired format and I'm open to non-LINQ solutions (although the purchase of 3rd party controls is not an option.) I suspect there is a way to leverage LINQ's grouping features, but I haven't been able to apply it to this scenario.

Nicole Castle
  • 410
  • 1
  • 4
  • 15

1 Answers1

0

I found a way to do dynamic pivots in SQL, but couldn't get it to work with two related tables, only with one. Dynamic SQL pivots here: http://www.simple-talk.com/blogs/2007/09/14/pivots-with-dynamic-columns-in-sql-server-2005/

Ultimately, I fell back and created a dataset manually. It's certainly not an optimized solution, but it gives the customer what they want. I wouldn't recommend this approach for a high volume of data.

I create the dataset and datatable fixed columns, then loop through the list of questions:

//get the list of questions
var context = new EventRegistrationEntities();
var customQuestions = from rf in context.tblRegistrationFields
                      where rf.EventID == vEventID
                      select new
                      {
                          RegistrationFieldID = rf.RegistrationFieldID,
                          FieldLabel = rf.FieldLabel
                      };

//add a question column for each question
List<string> extracolumns = new List<string>();

foreach (var q in customQuestions)
{
    dt.Columns.Add(q.FieldLabel, typeof(string));

    //store the question names for later user
    extracolumns.Add(q.RegistrationFieldID.ToString() + "-" + q.FieldLabel.ToString());
}

Next I then loop through the list of users and insert the fixed data, then within that loop (ugh) I add the users' answers:

foreach (var c in extracolumns) //these are the custom *questions*
{
    int regID = Convert.ToInt32(c.Substring(0, c.IndexOf("-")));
    string question = c.Substring(c.IndexOf("-") + 1); //we need to pass the question text (aka column header) in because if the user hasn't answered the question we have no access to it from here

    //get the question answer
    var userAnswer = (from urf in context.tblUserRegistrationFields.Include("tblRegistrationFields")
                      where urf.UserID == u.UserID && urf.RegistrationFieldID == regID
                      select new
                      {
                          Question = urf.tblRegistrationField.FieldLabel,
                          Answer = urf.value
                      }).FirstOrDefault();

     //add the answer to the data row
     if (userAnswer != null)
     {
         dr[question] = userAnswer.Answer.ToString();
     }
     else
     {
         dr[question] = ""; //if the user has not answered the question, insert a blank
     }
 }
Nicole Castle
  • 410
  • 1
  • 4
  • 15