Оператор "IN" в Linq

Я пытаюсь преобразовать старый необработанный запрос Sql в Linq с Entity Framework здесь.

Он использовал оператор IN с набором элементов. Запрос был примерно таким:

SELECT Members.Name
FROM Members
WHERE Members.ID IN ( SELECT DISTINCT ManufacturerID FROM Products WHERE Active = 1)
ORDER BY Members.Name ASC

Поскольку возврат подзапроса - это не одна строка, а набор строк, я не могу использовать метод String.Contains().

Я подумал о том, чтобы сделать что-то вроде:

var activeProducts = (
from products in db.ProductSet
where product.Active == true
select product.ManufacturerID);

а затем

var activeMembers = (
from member in db.ContactSet
where member.ID.ToString().Contains(activeProducts));

но он останавливается в содержимом, говоря, что имеет недопустимые аргументы... Я не могу выбрать activeProducts.ManufacturerID, потому что очевидно, что proprety не существует, поскольку он возвращает IQueryable...

В нижней строке, что я пытаюсь сделать здесь, нужно вернуть список членов, у которых есть хотя бы один активный продукт.

Любые подсказки?

[править]

Здесь полный код запроса... Я попробовал с содержимым во втором выражении, Linq, похоже, не понравилось:

Server Error in '/' Application. LINQ to Entities does not recognize the method 'Boolean Contains[String](System.Linq.IQueryable``1[System.String], System.String)' method, and this method cannot be translated into a store expression.

    var activeProduct =(from product in Master.DataContext.ProductSet
                        where product.Active == true
                           && product.ShowOnWebSite == true
                           && product.AvailableDate <= DateTime.Today
                           && ( product.DiscontinuationDate == null || product.DiscontinuationDate >= DateTime.Today )
                        select product.ManufacturerID.ToString() );

    var activeArtists = from artist in Master.DataContext.ContactSet
                        where activeProduct.Contains(artist.ID.ToString())
                        select artist;

    NumberOfArtists = activeArtists.Count();

    artistsRepeater.DataSource = activeArtists;
    artistsRepeater.DataBind();

[Подробнее] ПроизводительID - это нулевой GUID, видимо...

По какой-то причине класс ContactSet не содержит ссылок на продукты, которые, я думаю, мне нужно будет выполнить запрос соединения, никаких подсказок здесь.

Ответ 1

var activeMembers = (
from member in db.ContactSet
where activeProducts.Select(x=>x.ID).Contains(member.ID));

Ответ 2

Попробуйте where activeProducts.Contains(member.ID).
РЕДАКТИРОВАТЬ: вы пробовали его без каких-либо ToString s?

Ответ 3

Вы можете сделать это в одном запросе:

var q = from member in db.ContactSet
        where member.Products.Any(p => p.IsActive)
        select member;

Ответ 4

from m in members
where products.Any(p => p.Active && p.ManufacturerID == m.ID)
select m

или

from m in members
join p in products on m.ID equals p.ManufacturerID
where p.Active
select m

Ответ 6

Как насчет этого:

from m in members
where products.FirstOrDefault(prod => prod.IsActive == 1 && prod.Id == m.Id) != null
select m;

вы можете связать любое количество условий, требуемых в условии where, используя &&

Ash..

Ответ 7

Вместо этого:

var activeMembers = (
from member in db.ContactSet
where member.ID.ToString().Contains(activeProducts));

Попробуйте следующее:

var activeMembers = (
from member in db.ContactSet
where activeProducts.Contains(member.ID));

Ответ 8

Что делать, если вы меняете оператор (непроверенный)?

where activeProducts.Contains(member.ID)

Ответ 9

Как насчет этого...

var activeProducts = (
from products in db.ProductSet
where product.Active == true
select product.ManufacturerID);

var activeMembers = (
from member in db.ContactSet
where activeProducts.Contains(member.ID.ToString()));

Ответ 10

Вспомогательный метод или метод расширения будут отлично работать при запросе объектов в памяти. Но против базы данных SQL ваш код LINQ будет скомпилирован в дерево выражений, проанализирован и переведен в команду SQL. Эта функциональность не имеет понятия специально разработанных методов расширения или методов других объектов, таких как .Contains(...).

Он может быть легко реализован в стандартную функциональность LINQ-To-SQL от Microsoft. Но пока они не хотят, мы беспомощны, так как пока это не функциональность с открытым исходным кодом.

Все, что вы можете сделать, это создать свой собственный QueryProvider, который идет против базы данных SQL. Но это будет сложно, и только для этой функции in вам не хватает.

Однако, если вы действительно хотите пойти по этому маршруту, повеселитесь: LINQ: СОЗДАНИЕ СЕРИИ ИДЕАЛЬНЫХ ПРОВАЙДЕРОВ

Ответ 11

Наконец-то мне удалось закодировать что-то действительно уродливое, но это действительно работает! (Смеется)

    var activeProduct =(from product in Master.DataContext.ProductSet
                        where product.Active == true
                           && product.ShowOnWebSite == true
                           && product.AvailableDate <= DateTime.Today
                           && ( product.DiscontinuationDate == null || product.DiscontinuationDate >= DateTime.Today )
                        select product.ManufacturerID ).Distinct();

    var artists = from artist in Master.DataContext.ContactSet
                        select artist;

    List<Evolution.API.Contact> activeArtists = new List<Evolution.API.Contact>();

    foreach (var artist in artists)
    {
        foreach(var product in activeProduct)
        {
            if (product.HasValue && product.Value == artist.ID)
                activeArtists.Add(artist);
        }
    }

    NumberOfArtists = activeArtists.Count();

    artistsRepeater.DataSource = activeArtists;
    artistsRepeater.DataBind();

Ответ 12

var q = (from p in db.DOCAuditTrails
        where p.ActionUser == "MyUserID"
        && p.ActionTaken == "Not Actioned"
        && p.ActionDate > DateTime.Parse("2011-09-13")
          select p.RequisitionId).Distinct();

var DocAuditResults = db.DOCAuditTrails.Where(p 
  => q.ToArray().Contains(p.RequisitionId));

Ответ 14

Не зная точных сопоставлений, трудно сказать, что можно сделать и что не может. Я предполагаю, что никакого участия в кастинге нет. Во-первых, вы должны помнить, что все в дереве Linq Expression должно иметь эквивалент в SQL. Как отмечали некоторые другие, у вас есть объект. ToString() в ваших заявлениях Linq.

Однако кажется, что люди не обратили внимания на то, что у вас есть два способа использования объекта. ToSting(), оба из которых необходимо удалить.

Я бы также добавил дополнительную переменную, чтобы изменить тип захвата закрытия, чтобы быть явно из DataContext (так как оператор Linq похож на лямбда и с задержкой оценивается. Ему нужно будет взять всю основную переменную. что все в вашем Linq должно иметь эквивалент в SQL. Поскольку Master не может существовать в SQL, для типа Master не существует свойства DataContext/column/mapping.)

var context = Master.DataContext;
var activeProduct = from product in context.ProductSet
                    where product.Active == true
                       && product.ShowOnWebSite == true
                       && product.AvailableDate <= DateTime.Today
                       && ( product.DiscontinuationDate == null || product.DiscontinuationDate >= DateTime.Today )
                    select product.ManufacturerID;

var activeArtists = from artist in context.ContactSet
                    where activeProduct.Contains(artist.ID)
                    select artist;

Я надеюсь, что вышеупомянутые изменения будут работать для вас.

Во многих случаях проблемы с Linq для ORM можно проследить до вашего Linq Expression, захватив не primative (DateTime, int, string и т.д.) и не основанный на ORM класс (DataContext/EntityObject и т.д.). Другим важным преимуществом является использование функций и операторов, которые не отображаются ORM (возможно отображение функций, определенных пользователем, в .net-функцию через ORM, но я бы не рекомендовал его из-за проблем с индексацией).