Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/asp.net/32.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何将用于连接3个表的Linq查询转换为Linq方法并使用Include_C#_Asp.net_Linq - Fatal编程技术网

C# 如何将用于连接3个表的Linq查询转换为Linq方法并使用Include

C# 如何将用于连接3个表的Linq查询转换为Linq方法并使用Include,c#,asp.net,linq,C#,Asp.net,Linq,我看到过一些类似的帖子,但我还没有找到解决问题的方法。我在ASP.NET核心项目中有三个表。在我的处方和处方表上有一对多关系,在我的处方和营销表上有一对多关系。我想查询处方表并获取外键Prescribered,然后查询Prescriberes表并获取外键MarketerId并返回MarketerId。到目前为止我有这个linq 'var presciber = from p in _context.Prescriptions join f in _context

我看到过一些类似的帖子,但我还没有找到解决问题的方法。我在ASP.NET核心项目中有三个表。在我的处方和处方表上有一对多关系,在我的处方和营销表上有一对多关系。我想查询处方表并获取外键Prescribered,然后查询Prescriberes表并获取外键MarketerId并返回MarketerId。到目前为止我有这个linq

'var presciber = from p in _context.Prescriptions
                 join f in _context.Prescribers on p.PrescriberId equals f.Id
                 join m in _context.Marketers on f.MarketerId equals m.Id
                 where p.FolderStatusId == 3
                 select new { m.Id };
我希望能够使用.Include,这样我就可以包含来自Marketers表的其他数据,这样我就可以显示Marketers Name,而不是显示Marketers ID,并且在视图中不能为null。所以我想把这个查询转换成一个方法,我已经试过了

var prescriber = _context.Prescriptions
    .Join(_context.Prescribers,
    p => p.PrescriberId,
    f => f.Id,
    (p, f) => new { Prescriptions = p, Prescribers = f })
    .Join(_Context.Marketers,
    f => f.Prescribers.MarketerId,
    m => m.Id,
    (f, m) => new { Prescribers = f, Marketers = m })
    .Where(d => d.FolderStatusId == 3);//This line gets the error
在Where子句上,我得到了错误

<anonmyous type: <anonymous type:Prescription Prescriptions, Prescriber Prescribers> Prescribers, Marketer Marketers> does not contain a definition for FolderStatusId
这是处方课

public class Prescriber {
    public int Id { get; set; }
    public int MarketerId { get; set; }
    public string Name { get; set; }
    public virtual Marketer Marketer {get;set;}
    public virtual ICollection<Prescription> Prescriptions { get; set; }
}
这是营销人员课程

public class Marketer {
    public int Id { get;set; }
    public string Name { get; set; }
    public virtual ICollection<Prescriber> Prescribers { get; set; }
}

我的问题是如何更正此Linq方法,以及在何处添加.Include?

我的建议是使用对读者有任何意义的标识符。这将有助于您了解问题的原因:

var result = _context.Prescriptions
.Join(_context.Prescribers,
prescription => prescription.PrescriberId,
prescriber => prescriber.Id,
(prescription, prescriber) => new
{ 
    Prescription = prescription,
    Prescriber = prescriber,
})
// End of first join

.Join(_Context.Marketers,
firstJoinResult => firstJoinResult.Prescriber.MarketerId,
marketer => marketer.Id,

(firstJoinResult, marketer) => new
{
    Prescription = prescription,
    Prescriber = prescriber,
    Marketer = marketer,
})
// end of second join

.Where(secondJoinResult => secondJoinResult.FolderStatusId == 3);
//This line gets the error
您的第二个联接结果没有属性FolderStatusId。在原始代码中,您使用标识符d来引用第二个联接结果。只有处方具有FolderStatusId。因此,您的位置应该是:

.Where(secondJoinResult => secondJoinResult.Prescription.FolderStatusId == 3);
还有改进的余地 在连接之前使用Where 如果您在开始加入之前使用Where,那么许多处方根本不需要加入:

var result = _context.Prescriptions
    .Where(prescription => prescription.FolderStatusId == 3);
    .Join(_context.Prescribers,
        prescription => prescription.PrescriberId,
        prescriber => prescriber.Id,
        ... // etc
仅选择您计划使用的属性 所以一个营销人员有零个或多个处方,而每个处方都有零个或多个处方,就像你说的:一对多的关系

营销商的每一个处方[14]都有一个值为14的外键营销商ID。如果营销商[14]有1000张处方,那么您将把营销商[14]与其中一张带有营销商ID的处方[14]的组合转移1000倍

除了传输1000倍于相同营销人员数据的事实之外,您还可以传输相同的Prescription.MarketerId值,您已经知道它的值:它有值[14]。多么浪费处理能力啊

解决方案:仅选择您计划使用的属性:

    var result = _context.Prescriptions
    .Where(prescription => prescription.FolderStatusId == 3);
    .Join(_context.Prescribers,
        prescription => prescription.PrescriberId,
        prescriber => prescriber.Id,
        ... // etc
        (firstJoinResult, marketer) => new
        {
            Marketer = new
            {
                // Select only the Marketer properties that you plan to use
                Id = marketer.Id,
                Name = markter.Name,
                ...
            }

            Subscriber = new
            {
                // Again: only the properties that you plan to use:
                Id = firstJoinResult.Subscriber.Id,
                Name = markter.Name,

                // No need for this, you  know the value:
                // MarketerId = firstJoinResult.Subscriber.MarketerId,
            },

            Prescription = new { ... },
       });
在实体框架中,始终使用Select查询数据,并仅选择您计划使用的属性。仅当您计划更改包含的数据时才使用“包含”

原因是,实体框架只能更新完全获取的项

考虑组连接 我在上一章已经提到:营销者的相同价值观将被多次转移

当你想让他们的子项目,比如学校和他们的学生,客户的订单,和营销人员与他们的处方,考虑组加入,而不是加入。< /P>

var result = _context.Marketers
    .GroupJoin(_context.Prescribers,
        marketer => marketer.Id,
        prescriber => prescriber.MarketerId,

        // parameter ResultSelector:
        // get all Marketers with their prescribers to make one new
        (marketer, prescribersOfThisMarketer) => new
        {
            Id = marketer.Id,
            Name = marketer.Name,
            ...

            Prescribers = prescribersOfThisPrescription.GroupJoin(
                _context.Prescriptions.Where(prescription => prescription.FolderStatusId == 3),
                prescriber => prescriber.Id,
                prescription => prescription.PrescriberId,

                // from every prescriber with all its prescriptions, make one new
                (prescriber, prescriptionsOfThisPrescriber) => new
                {
                    Id = prescriber.Id,
                    Name = prescriber.Name,
                    ...

                    Prescriptions = prescriptionsOfThisPrescriber.Select(presription => new
                    {
                         Id = prescription.Id,
                         ...
                    })
                    .ToList(),
                })
                .ToList(),
        });
所以不是

Marketer  Subscriber
   A          10
   A          11
   B          20
   A          28
   C          12
   B          13
你会得到:

营销者A及其订户10、11、28 营销人员B及其订户20、13 营销人员C和他的订户12 营销商没有任何订户 这看起来更像是你想要的结果

注意:GroupJoin还将返回没有子项的项!,就像没有订户的营销人员一样。通常您希望这样做,但如果您不希望这样做,请使用Where将其过滤掉:

.Where(marketer => marketer.Subscribers.Any());
最具革命性的:使用ICollection! 有人告诉我EF core不支持这一点。我知道完整实体框架肯定会这样做:使用ICollections而不是组联接

要求给我一些所有营销人员的属性,每个人都有他所有处方的属性,每个人都有他的处方

var marketers = dbContext.Marketers.Select(marketer => new
{
    Id = marketer.Id,
    Name = marketer.Name,
    ...

    Prescribers = marketer.Prescribers.Select(prescriber => new
    {
        Id = prescriber.Id,
        Name = prescriber.Name,
        ...

        Prescriptions = prescriber.Prescriptions
            .Where(prescription => prescription.FolderStatusId == 3)
            .Select(prescription => new
            {
                 Id = prescription.Id,
                 ...
            })
            .ToList(),
    })
    .ToList(),
});

这种感觉比加入团体更自然。实体框架知道表之间的关系,并将其转换为正确的组联接。

请添加实体定义。Include用于导航属性,而不是用于其他列,因此您只需在select中添加所需的所有列。说到导航属性,我建议考虑使用它们而不是加入,我添加了模型类,并将研究导航。您有导航属性,那么为什么要加入?我愿意学习更好的解决方案。我使用join是因为我认为这是一种方式,但我不一定只限于join这很好,谢谢!比我想象的要多得多。
var marketers = dbContext.Marketers.Select(marketer => new
{
    Id = marketer.Id,
    Name = marketer.Name,
    ...

    Prescribers = marketer.Prescribers.Select(prescriber => new
    {
        Id = prescriber.Id,
        Name = prescriber.Name,
        ...

        Prescriptions = prescriber.Prescriptions
            .Where(prescription => prescription.FolderStatusId == 3)
            .Select(prescription => new
            {
                 Id = prescription.Id,
                 ...
            })
            .ToList(),
    })
    .ToList(),
});