简体   繁体   中英

C# LINQ query to data from multiple tables

I have 2 tables:

Metrics (id, Metric) :[{1,Metric1},{2,Metric2},{3,Metric3}]

id | Metric
------------------------------------------------------------
1  |  Metric1
2  |  Metric2
3  |  Metric3

MetricsValuePerPerson (id, PersonId, Metricid, Value)

id | PersonId | Metricid | Value
------------------------------------------------------------
1  |  1       |     1    |  P1metric1Value
2  |  1       |     2    |  P1Metric2Value
3  |  1       |     3    |  P1metric3Value
4  |  2       |     1    |  P2Metric1Value
5  |  2       |     2    |  P2metric2Value
6  |  2       |     3    |  P2Metric3Value

I want to show the values in a grid where each row is a Person and each column is a Metric :

PersonId | Metric1         | Metric2        | Metric3
------------------------------------------------------------
P1       |  P1metric1Value | P1Metric2Value | P1Metric3Value
P2       |  P2metric1Value | P2Metric2Value | P2Metric3Value

Here is how I try to load the store:

var metricValues = from mv in dc.MetricsValuePerPerson
                   join m in dc.Metrics on mv.Metricid equals m.id
                   select new { Personid = mv.Personid, Metric1 = (codesnippet) , Metric2 = (codesnippet), Metric3 = (codesnippet) };

How can I replace (codesnippet) to get the Value of Metricx ?

In LINQ, provided you have established relations in the database, you very rarely need to use JOIN keyword. In your case, within the DB you have relation between MetricsValuesPerPerson and Metrics, right? If so then:

var metricValues = from mv in dc.MetricsValuePerPerson
                   select new { 
                    Personid = mv.Personid, 
                    Metric1 = mv.Metric.Metric };

The result doesn't seem to be meaningful though (probably you would want to add Value too).

EDIT: This would be like a pivot, assuming you only have 3 metrics and at most 1 from each type of metric per person (ie: there is no personId, metricId, value like (1,1,10) and (1,1,20).

var result = from mv in MetricsValuePerPersons.Where(mvpp => mvpp.Metricid == 1)
                 let mv2 = MetricsValuePerPersons.SingleOrDefault(mvpp => mvpp.PersonId == mv.PersonId && mvpp.Metricid == 2)
                 let mv3 = MetricsValuePerPersons.SingleOrDefault(mvpp => mvpp.PersonId == mv.PersonId && mvpp.Metricid == 3)
                 select new {
        PersonId = mv.PersonId,
        Metric1 = mv.Value,
        Metric2 = mv2.Value,
        Metric3 = mv3.Value,
    };

You can do this by using GroupJoin (equivalent to LEFT JOIN in SQL). Join the MetricsValuePerPerson with Metrics and then GroupBy by the PersonId then Select the result. The sample code is in Lambda Join , but you can convert this to LINQ .

Working sample : C# Fiddle

var result = metricValuePerPerson.GroupJoin(metrics, mv => new { Id = mv.PersonId }, m => new { Id = m.Id }, 
        (mv, m) => new { mv = mv, m = m })
        .SelectMany(x => x.m.DefaultIfEmpty(), (x, y) => new {mv = x.mv, m = y })
        .GroupBy(g => g.mv.PersonId)
        .Select(x =>  
        {
           var grouped = x.ToList();
           return new 
            {
                PersonId = x.Key, //The below are sample code, please use your actual code.
                Metric1 = grouped[0].mv.PersonId + "|" + grouped[0].m.Metric + "|" + grouped[0].mv.Value,
                Metric2 = grouped[1].mv.PersonId + "|" + grouped[1].m.Metric + "|" + grouped[1].mv.Value,
                Metric3 = grouped[2].mv.PersonId + "|" + grouped[2].m.Metric + "|" + grouped[2].mv.Value,
            };
        })
        .ToList();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM