2014-12-01 2 views
0

У меня есть объект «IdentityProvider» и «IdentityProvider» имеет дочерние домены.Поиск foo или bar с расширениями Linq

class IdentityProvider 
{ 
    ... 
    public virtual ICollection<Domain> Domains { get; set; } 
    ... 
} 

class Domain 
{ 
    ... 
    public string Name { get; set; } 
    ... 
} 

Существует поймать все доменам под названием «*»

Использование Linq Extensions, мне нужно найти все IdentityProviders, которые имеют либо указанный домен или IdentityProviders, которые имеют улов все, но ни как ,

Как бы я сформировал свой запрос?

+2

Как выглядит «IdentityProvider»? Определение типа? Любой код, который вы уже пробовали ..? –

+0

@RahulSingh Добавлено определение класса ... Я пробовал множество комбинаций, но ничего не работает в это время. – Jamie

ответ

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() 
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; 

Вы можете попробовать использовать XOR (^) вместо этого в where пункте:

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 вы сталкиваетесь ...).

+0

Они очень близки, но catchall также возвращается, когда есть совпадение домена. – Jamie

+0

Linq Source - это SQL-сервер через EntityFramework 6 – Jamie

-1

пожалуйста, попробуйте

identityProviders.Where(ip=>ip.Domains.Any(d=>d.Name=="SearchDomain" || d.Name=="*")) 
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; 
}) 
+0

Я, вероятно, не использую это правильно, так как получаю сообщение об ошибке: выражение лямбда с телом оператора не может быть преобразовано в дерево выражений – Jamie

+0

@Jamie Это потому, что вы используете Entity Framework и он пытается преобразовать запрос в SQL, поэтому вы не можете использовать этот метод. – nmclean

0

Если сгруппировать данные по доменам, которые имеют улов все такие, как:

var grouped = ipProviders.Domains 
         .GroupBy (dm => dm.Name == "*"); 

Тогда вы можете вернуть все стопорные Alls сразу или извлечь целевые домены с точным названием, такие как

var targetDomain = "Jabberwocky"; 

var targets = grouped.Where (gr => gr.Key == (targetDomain == "*")) 
        .Select (gr => gr.Where (dm => dm.Name == targetDomain)); 

группировка выглядит следующим образом с данными Jabberwocky, OmegaMan и два домена с *

enter image description here

0

Ответ, который вы дали, не дает вам то, о чем вы просили в вопросе. Вы сказали, что хотите поставщиков, у которых был тот или другой, но не оба.

Во-первых, если провайдер как он будет быть выбран этим кодом, так как первое условие истинно:

d.Domains.Any(n => n.Name == domain && domExists) 

Во-вторых, если поставщик имеет улов-все, но не указанный домен , то будет не, если домен существует в различных провайдерах. Это происходит потому, что domExists будет истинным, поэтому вторая проверка потерпит неудачу:

d.Domains.Any(n => n.Name == "*" && !domExists) 

Я не вижу, как захватывая domExists флаг может реально помочь вам. Однако я думаю, что начать с поиска всей коллекции доменов - это правильная идея. Вы можете попробовать это:

Во-первых, собрать все идентификаторы поставщиков для доменов, которые соответствуют либо «*», либо имя (я предполагаю, что домен должен иметь внешний ключ к IdentityProvider):

var providerIds = 
    db.Domains.Where(d => d.Name == domain || d.Name == "*") 
    .Select(d => d.IdentityProviderID) 
    .ToList(); 

Это сужает это вниз довольно много, и у нас есть способ фильтрации снова: есть поставщики, которые имеют как будут добавлены в список дважды, так что мы просто должны выбрать все идентификаторы, которые появляются только один раз:

var uniqueProviderIds = 
    providerIds.GroupBy(id => id) 
    .Where(g => g.Count() == 1) 
    .Select(g => g.Key) 
    .ToList(); 

даст вам ответ. Вы также можете использовать этот список для создания другого SQL-запроса, чтобы получить фактические объекты IdentityProvider, если они вам понадобятся:

db.IdentityProviders.Where(ip => uniqueProviderIds.Contains(ip.ID)).ToList() 
Смежные вопросы