C# 如何将用于连接3个表的Linq查询转换为Linq方法并使用Include
我看到过一些类似的帖子,但我还没有找到解决问题的方法。我在ASP.NET核心项目中有三个表。在我的处方和处方表上有一对多关系,在我的处方和营销表上有一对多关系。我想查询处方表并获取外键Prescribered,然后查询Prescriberes表并获取外键MarketerId并返回MarketerId。到目前为止我有这个linqC# 如何将用于连接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
'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(),
});