Entity framework 如果第一个linq查询返回空,如何从另一个查询列表中获取结果?
在这个EF查询中,对于联系人列表,我试图查询以获取ContactTypeA的记录,并在联系人列表中填充结果。若ContactTypeA并没有记录,那个么我希望它查询ContactTypeB的记录并将结果填充到contacts列表中。我尝试使用DefaultIfEmpty,但该方法只接受单个值,不接受列表“联系人”是一个列表对象。有什么想法,甚至是DefaultIfEmpty的替代方案吗?谢谢Entity framework 如果第一个linq查询返回空,如何从另一个查询列表中获取结果?,entity-framework,linq,Entity Framework,Linq,在这个EF查询中,对于联系人列表,我试图查询以获取ContactTypeA的记录,并在联系人列表中填充结果。若ContactTypeA并没有记录,那个么我希望它查询ContactTypeB的记录并将结果填充到contacts列表中。我尝试使用DefaultIfEmpty,但该方法只接受单个值,不接受列表“联系人”是一个列表对象。有什么想法,甚至是DefaultIfEmpty的替代方案吗?谢谢 select(i => new transaction{ .... contacts = con
select(i => new transaction{
....
contacts = contactRepository.All.Where(c => c.AccountId == i.Account.Id && contactTypeRepository.All.Any(ct => ct.ContactId == c.Id && ct.Type == ContactType.ContactTypeA)).ToList().DefaultIfEmpty((contactRepository.All.Where(c => c.AccountId == i.Account.Id && contactTypeRepository.All.Any(ct => ct.ContactId == c.Id && ct.Type == ContactType.ContactTypeB)).ToList()
}
)
首先,确保您的
contactRepository.All()
方法返回IQueryable
而不是IEnumerable
、IList
等,否则您将自动将所有联系人加载到内存中
从这里开始,不要害怕跨多个语句简化查询,以使其更易于理解。您还应该利用导航属性,而不是依赖于完全断开连接的实体和通用存储库,并手动将它们连接到大型表达式中
理想情况下,帐户可以有一组联系人,但如果没有,则联系人至少应具有ContactType引用:
var accountContactsQuery = contactRepository.All
.Where(c => c.AccountId == i.AccountId); //Remains IQueryable
var contacts = accountContactsQuery
.Where(c => c.ContactTypes.Any(ct => c.Type == ContactType.ContactTypeA)
.ToList(); // Gets List of Contacts where contains at least 1 ContactTypeA type.
// If we have none, replace with results for ContactTypeB
if (!contacts.Any())
contacts = accountContactsQuery
.Where(c => c.ContactTypes.Any(ct => c.Type == ContactType.ContactTypeB)
.ToList();
这看起来有点奇怪,因为您的ContactType似乎有一个ContactId(与包含ContactTypeId的Contact相反?),但上面反映了示例中的关系
使用包含联系人集合的帐户:
var accountContactsQuery = accountRepoitory.All
.Where(a => true /* replace with relevant criteria */);
var contacts = accountContactsQuery
.SelectMany(a => a.Contacts)
.Where(c => c.ContactTypes.Any(ct => c.Type == ContactType.ContactTypeA)
.ToList(); // Gets List of Contacts where contains at least 1 ContactTypeA type.
// If we have none, replace with results for ContactTypeB
if (!contacts.Any())
contacts = accountContactsQuery
.SelectMany(a => a.Contacts)
.Where(c => c.ContactTypes.Any(ct => c.Type == ContactType.ContactTypeB)
.ToList();
在处理表达式中的条件时,我可以建议返回所有相关细节,然后根据条件构建最终的“有效载荷”
例如,如果查询帐户以生成事务,但希望加载ContactAs(如果可用)和Bs(如果不可用):
var transactionData = accountRepoitory.All
.Where(a => true /* replace with relevant criteria */);
.Select(a => new
{
a.AccountId,
/* populate account and common details.. */
ContactAs = a.Contacts
.Where(c => c.ContactTypes.Any(ct => c.Type == ContactType.ContactTypeA).ToList(), // Consider a Select to get relevant details...
ContactBs = a.Contacts
.Where(c => c.ContactTypes.Any(ct => c.Type == ContactType.ContactTypeB).ToList()
}).ToList(); // Executes query against DB to load relevant data...
var transactions = transactionData
.Select( t => new Transaction
{
AccountId = t.AccountId,
/* Other fields */
Contacts = t.ContactAs.Any() ? t.ContactAs : t.ContactBs
}).ToList();
基本上使用EF Linq表达式加载可能的数据,因此包括ContactA和ContactB的结果,然后使用该数据构建最终投影,并根据需要有条件地使用ContactA或B。一般来说,我不建议将实体传递回(实际的联系人实体),而是使用
Select
在第一个EF查询中投影到最小可行的视图模型中。谢谢您的回答,但正如您所看到的,我的代码在linq Select语句中(请注意顶行)。因此,我不能使用语句或变量。在构建条件种群时,我已经扩展了要考虑的选项的答案,以选择两种场景的细节,然后从这些结果构建最终的投影。(在内存中)使用中间Select
(作为LINQ查询语法let
)捕获ContactTypeA
,然后使用条件表达式:。选择(i=>new{i,ContactAs=ContactTypeAs})。选择(ica=>new transaction{…,contacts=ica.ContactAs.Any()?ContactAs:ContactTypeBs})
-我不保证这可以由EF翻译成SQL(取决于EF的版本)