LINQ / EF: концептуальное / механическое выполнение нескольких объединений, которые возвращают как сущность, так и вычисленное значение - PullRequest
0 голосов
/ 26 ноября 2011

Я надеюсь, что кто-то может помочь мне с блоком мозга, который у меня есть, о том, как сделать несколько соединений с EF, который возвращает сущность, где одно из полей вычисляется по запросу. Я придумал (в значительной степени бесполезный) пример в надежде, что кто-нибудь может помочь мне понять, как это должно быть сделано.

Я хотел бы вернуть список объектов ISP из DBContext со свойством «TotalUsed», заполненным запросом LINQ. Я успешно выполнил соединения (тривиально) и поиграл с группировкой и суммой, но, похоже, не совсем правильно понял.

Общая идея этого надуманного примера заключается в том, что сетевые адаптеры подключены к одному и только одному маршрутизатору, а несколько маршрутизаторов подключены к одному провайдеру.

Как написать запрос LINQ, который суммирует пропускную способность, необходимую для каждого провайдера, наряду с другими свойствами этого провайдера?

Ожидаемый вывод будет список ISP, который может выглядеть {{1, "foo", 52}, {2, "bar", 345}, {3, "foobar", 621}}, где третье свойство является суммой свойства BandwidthNeeded на всех сетевых картах, транзитивно связанных с ISP .

Занятия:

public class ISP
{
   public int ISPid {get; set;}
    public int ISPName {get; set;}
    public int TotalUsed {get; set;}  // not mapped to DB -> should populate via LINQ
}

public class Router
{
    public int RouterId {get; set;}
    public string RouterName {get; set;}
    public int ISPId {get; set;} // foreign key for ISP
}  

public class Nic
{
    public int NicId { get; set; }
    public string NicLocation { get; set; }
    public int BandwidthUsed { get; set; }
    public int RouterId {get; set; }  // foreign key for router
}

Ответы [ 3 ]

2 голосов
/ 26 ноября 2011

Если вы переместите свойство TotalUsed в отдельный тип, вы можете сделать это (прошу прощения за любые опечатки):

public class ISP // mapped
{
    public int ISPid {get; set;}
    public int ISPName {get; set;}
}
public class ISPWithTotalUsed : ISP // not mapped
{
    public int TotalUsed { get; set; }
}
var query = (from ISP in context.ISPs
             select new ISPWithTotalUsed
             {
                 ISPid = ISP.ISPid,
                 ISPName = ISP.ISPName,
                 TotalUsed = (from router in context.Routers
                              where router.ISPid == ISP.ISPid
                              from nic in context.Nics
                              where nic.RouterId == router.RouterId
                              select nic.BandwidthUsed).Sum()
             });

Если вы добавите свойства навигации, это можно сделать несколько более читабельным, удалив ссылки на ID.

0 голосов
/ 26 ноября 2011

Примерно так должно работать:

var query = context.ISPS.Select(isp => new{ ISP : isp, Used : isp.Routes.Sum(r => r.Nics.Sum(n => n.BandwidthUsed))}).ToList();

var result = query.Select(item => {
   item.ISP.TotalUsed = item.Used;
   return item.ISP;
}).ToList();

Я бы навсегда удалил свойство TotalUsed из ISP и вместо этого создал бы класс-обертку, который бы содержал как ISP, так и TotalUsed. Тогда вы можете удалить второй запрос. (EF не позволит вам создать объект внутри запроса объекта).

0 голосов
/ 26 ноября 2011
var context = new IspContext();
var groups = context.Nics.Include("Router.Isp").GroupBy(n => n.Router.ISPId).ToList();
var result = groups.Select(g => new() 
             { 
                 Key = g.Key, 
                 Name = g.FirstOrDefault().Router.Isp.IspName, 
                 Total = g.Sum(n => n.BandwithUsed)
             });

Это работает для вас?Название вещь не красивая, и вы можете получить все это в одном запросе.Трудно сказать, работает ли он быстрее, хотя.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...