Declare and initialize variable for assigning list of anonymous types

Viewed 135

I try to join two tables:

var data = from request in context.Requests
                        join account in context.AutolineAccts
                            on request.PkRequest.ToString() equals account.AccountCode
                        select new 
                        {
                            ID = request.PkRequest.ToString(),
                            Location = request.FkLocation,
                            RequestDate = request.RequestDate.Value,
                            Requestor = request.FkRequestor,
                            DebitorNr = request.FkDebitor.ToString(),
                            NewDebit = request.Debit.ToString(),
                            ApprovalStatus = request.ApprovalStatus.ToString(),
                            RecommendationStatus = request.RecommendationStatus.ToString(),
                            DebitorName = account.CustomerSname,
                            Limit = account.CreditLimit
                        };

Now I want to filter the result set depending on the status of the user:

// Accounting user
if (ActiveDirectoryHelper.CheckIfUserIsInADGroup(userLogin, AdGroups.ACCOUNTING) )

    req = data.Where(x => x.RecommendationStatus == null).ToList();

// After sales manager
else if (ActiveDirectoryHelper.CheckIfUserIsInADGroup(userLogin, AdGroups.SAV_LEADERS))
    req = data.OrderByDescending(x => x.ID).ToList();

// Everybody else
else 
    req = data.OrderByDescending(x => x.PkRequest).ToList();

And that's where I'm stuck. When I don't have the join and only retrieve a "Request" type, I can just declare a list of Requests

List<Requests> req;

But with that combination of Requests and AutolineAccts I would have to declare and initialize a list of "items" (req) to assign the result set to in the if-else segments. But I don't know how that anonymous variable should look like.

Later on I have to map the result set to a list of my IndexViewModels:

foreach (var item in req)
                viewModel.CLModels.Add(new IndexViewModel
                {
                    ID = item .PkRequest.ToString(),
                    Location = item .FkLocation,
                    RequestDate = item .RequestDate.Value,
                    Requestor = item .FkRequestor,
                    DebitorNr = item .FkDebitor.ToString(),
                    NewDebit = item .Debit.ToString(),
                    ApprovalStatus = item .ApprovalStatus.ToString(),
                    RecommendationStatus = item .RecommendationStatus.ToString(),
                    DebitorName = item.CustomerSname,
                    Limit = item.CreditLimit
                });

Any idea to solve this issue?

2 Answers
IEnumerable<dynamic> result = from request in requests
                    join account in accounts
                        on request.id equals account.id
                        select new {id=request.id, name=account.name};

Keeps the accessors, can further be queried and be return type of a method.

enter image description here

One option to avoid dynamic is to give the compiler an example of your anonymous type:

var req = new[]
{
    new
    {
        ID = "",
        Location = "",
        RequestDate = DateTime.Now,
        Requestor = "",
        DebitorNr = "",
        NewDebit = "",
        ApprovalStatus = "",
        RecommendationStatus = "",
        DebitorName = "",
        Limit = 0
    }
}.ToList();

Obviously you should adjust the values to match the type that you expect.

It's a bit ugly, but personally I'd prefer that over using dynamic typing.

If you wanted to avoid actually allocating the array and the list, you could use type inference in a fairly horrible way:

// Simple method that returns null, but enables type inference
public static List<T> ProvideNullList(T sample) => null;

// Call it when you want to declare your variable:
var sample = new
{
    ID = "",
    Location = "",
    RequestDate = DateTime.Now,
    Requestor = "",
    DebitorNr = "",
    NewDebit = "",
    ApprovalStatus = "",
    RecommendationStatus = "",
    DebitorName = "",
    Limit = 0
};
var req = GenericHelpers.ProvideNullList(sample);

That does still allocate the sample, but it's at least a bit better than the array and list as well.

Related