Ответ 1
var activeMembers = (
from member in db.ContactSet
where activeProducts.Select(x=>x.ID).Contains(member.ID));
Я пытаюсь преобразовать старый необработанный запрос 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 не содержит ссылок на продукты, которые, я думаю, мне нужно будет выполнить запрос соединения, никаких подсказок здесь.
var activeMembers = (
from member in db.ContactSet
where activeProducts.Select(x=>x.ID).Contains(member.ID));
Попробуйте where activeProducts.Contains(member.ID)
.
РЕДАКТИРОВАТЬ: вы пробовали его без каких-либо ToString
s?
Вы можете сделать это в одном запросе:
var q = from member in db.ContactSet
where member.Products.Any(p => p.IsActive)
select member;
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
Попробуйте решение, отправленное Colin Meek по адресу: http://social.msdn.microsoft.com/forums/en-US/adodotnetentityframework/thread/095745fe-dcf0-4142-b684-b7e4a1ab59f0/. Это сработало для меня.
Как насчет этого:
from m in members
where products.FirstOrDefault(prod => prod.IsActive == 1 && prod.Id == m.Id) != null
select m;
вы можете связать любое количество условий, требуемых в условии where, используя &&
Ash..
Вместо этого:
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));
Что делать, если вы меняете оператор (непроверенный)?
where activeProducts.Contains(member.ID)
Как насчет этого...
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()));
Вспомогательный метод или метод расширения будут отлично работать при запросе объектов в памяти. Но против базы данных SQL ваш код LINQ будет скомпилирован в дерево выражений, проанализирован и переведен в команду SQL. Эта функциональность не имеет понятия специально разработанных методов расширения или методов других объектов, таких как .Contains(...)
.
Он может быть легко реализован в стандартную функциональность LINQ-To-SQL от Microsoft. Но пока они не хотят, мы беспомощны, так как пока это не функциональность с открытым исходным кодом.
Все, что вы можете сделать, это создать свой собственный QueryProvider, который идет против базы данных SQL. Но это будет сложно, и только для этой функции in
вам не хватает.
Однако, если вы действительно хотите пойти по этому маршруту, повеселитесь: LINQ: СОЗДАНИЕ СЕРИИ ИДЕАЛЬНЫХ ПРОВАЙДЕРОВ
Наконец-то мне удалось закодировать что-то действительно уродливое, но это действительно работает! (Смеется)
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();
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));
Я уже опубликовал примерно то же самое http://www.codeproject.com/Tips/336253/Filtering-records-from-List-based-similar-to-Sql-I
Не зная точных сопоставлений, трудно сказать, что можно сделать и что не может. Я предполагаю, что никакого участия в кастинге нет. Во-первых, вы должны помнить, что все в дереве 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, но я бы не рекомендовал его из-за проблем с индексацией).