在此EF查询中,对于联系人列表,我试图查询以获取ContactTypeA的记录并在联系人列表中填充结果。如果没有ContactTypeA的记录,那么我希望它查询ContactTypeB的记录并在联系人列表中填充结果。我尝试使用DefaultIfEmpty,但是该方法仅接受单个值,而不接受列表。 “联系人”是一个列表对象。有什么想法,甚至可以替代DefaultIfEmpty吗?谢谢。
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()
}
)
答案 0 :(得分:0)
首先,请绝对确保您的contactRepository.All()
方法返回IQueryable<Contact>
而不返回IEnumerable<Contact>
,IList<Contact>
等,否则您将自动加载 all 联系人进入内存。
从那里开始,不要害怕跨多个语句简化查询以使其更容易理解。您还应该利用导航属性,而不是依赖完全断开连接的实体和通用存储库,并手动将它们全部组合成巨大的表达式。
理想情况下,一个帐户可以具有一组联系人,但如果没有,则至少联系人应该具有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,(相对于Contact中包含一个ContactTypeId?),但这在您的示例中反映了这种关系。
对于包含联系人集合的帐户:
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();
在处理表达式中的条件时,我建议返回所有相关详细信息,然后根据条件构建最终的“有效载荷”。
例如,如果查询帐户以建立交易,但希望加载ContactA(如果可用),并希望为每个帐户加载B(如果不可用):
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查询中将其投影到最低可行的视图模型中。