我有一个对象“IdentityProvider”,“IdentityProvider”有子域名。
class IdentityProvider
{
...
public virtual ICollection<Domain> Domains { get; set; }
...
}
class Domain
{
...
public string Name { get; set; }
...
}
有一个名为“*”的所有域名
使用Linq Extensions,我需要找到所有具有指定域的IdentityProviders,或者找到具有catch all的所有IdentityProviders,但也不是两者。
我如何形成我的查询?
答案 0 :(得分:2)
这样的事情应该成功:
from i in identityProviders
let hasDomain = i.Domains.Any(d => d.Name == domainName)
let hasCatchAll = i.Domains.Any(d => d.Name == "*")
where (hasDomain && !hasCatchAll) || (!hasDomain && hasCatchAll)
select i;
您可以尝试在where
子句中使用XOR (^
):
from i in identityProviders
let hasDomain = i.Domains.Any(d => d.Name == domainName)
let hasCatchAll = i.Domains.Any(d => d.Name == "*")
where hasDomain ^ !hasCatchAll
select i;
但是我不确定它是否被你的提供者翻译成了SQL(你没有指定你正在处理哪种LINQ源......)。
答案 1 :(得分:0)
使用标准LINQ函数无法检查您的条件,而不会两次迭代Domains
集合,这是不必要的低效率。我会使用像这样的自定义过滤器函数,迭代一次,如果找到两者就提前失败:
identityProviders.Where(identityProvider => {
bool hasDomain = false, hasCatchAll = false;
foreach (var domain in identityProvider.Domains) {
hasDomain = hasDomain || domain.Name == domainName;
hasCatchAll = hasCatchAll || domain.Name == "*";
if (hasDomain && hasCatchAll) return false;
}
return hasDomain || hasCatchAll;
})
答案 2 :(得分:0)
如果您按照包含所有内容的域对数据进行分组,例如:
var grouped = ipProviders.Domains
.GroupBy (dm => dm.Name == "*");
然后,您可以立即返回所有catch alls或提取具有确切名称的目标域,例如
var targetDomain = "Jabberwocky";
var targets = grouped.Where (gr => gr.Key == (targetDomain == "*"))
.Select (gr => gr.Where (dm => dm.Name == targetDomain));
对于Jabberwocky
,OmegaMan
以及*
答案 3 :(得分:0)
感谢那些回答的人,你在其他领域帮助了我,但是对于这个问题,我最终做了以下,可能不是最好的方法,但它有效:
查看域名是否存在:
var domExists = db.Domains.Any(d => d.Name == domain);
查找域存在的所有身份提供者和domExists或查找通配符而不是domExists。
IdentityProviders.Where(d =>
d.Domains.Any(n => n.Name == domain && domExists) ||
d.Domains.Any(n => n.Name == "*" && !domExists)
).Any()
答案 4 :(得分:0)
您给出的答案并不能解决您在问题中提出的要求。你说你想要的提供者有一个或另一个但不是两个。
首先,如果提供者同时拥有这两者,则此代码将选择 ,因为第一个条件为真:
d.Domains.Any(n => n.Name == domain && domExists)
其次,如果提供程序具有catch-all但不是指定的域,则如果该域存在于不同的提供程序中,则不将被选中。这是因为domExists
将为真,因此第二次检查将失败:
d.Domains.Any(n => n.Name == "*" && !domExists)
我不知道捕捉domExists
旗帜如何真正帮助你。但是,我认为从搜索整个域名集合开始是正确的想法。你可以试试这个:
首先,收集与&#34; *&#34;匹配的域的提供商的所有ID。或者名称(我假设Domain必须有一个IdentityProvider的外键):
var providerIds =
db.Domains.Where(d => d.Name == domain || d.Name == "*")
.Select(d => d.IdentityProviderID)
.ToList();
这缩小了很多,我们有一种方法可以再次过滤它:任何两个的提供者都会被添加到列表中两次,所以我们只需要选择所有只出现一次的ID:
var uniqueProviderIds =
providerIds.GroupBy(id => id)
.Where(g => g.Count() == 1)
.Select(g => g.Key)
.ToList();
现在uniqueProviderIds.Any()
会给你答案。您还可以使用此列表构建另一个SQL查询,以便在需要时获取实际的IdentityProvider对象:
db.IdentityProviders.Where(ip => uniqueProviderIds.Contains(ip.ID)).ToList()
答案 5 :(得分:-1)
请尝试
identityProviders.Where(ip=>ip.Domains.Any(d=>d.Name=="SearchDomain" || d.Name=="*"))