Запрос OData "where ID in list"
У меня есть служба OData, где я пытаюсь отфильтровать список идентификаторов; эквивалент SQL будет примерно таким:
SELECT * FROM MyTable WHERE TableId IN (100, 200, 300, 400)
Свойство, которое я пытаюсь фильтровать, набирается как Int32. Я пробовал следующее, что дает мне ошибку "Operator" add 'несовместим с типами операндов "Edm.String" и "Edm.Int32":
string ids = ",100,200,300,400,";
from m in provider.Media where ids.Contains("," + t.media_id + ",")
а также
string ids = ",100,200,300,400,";
from m in provider.Media where ids.Contains("," + t.media_id.ToString() + ",")
и
string ids = ",100,200,300,400,";
from m in provider.Media where ids.Contains("," + Convert.ToString(t.media_id) + ",")
и
string ids = ",100,200,300,400,";
from m in provider.Media where ids.Contains(string.Concat(",", t.media_id, ","))
Как вы можете видеть, в настоящее время я использую LINQ для запроса службы.
Есть ли способ, которым я могу сделать то, что я пытаюсь сделать, или я задерживаю построение текстового фильтра и использование AddQueryOption и повторяю его через список и добавляя вручную предложения или ссылки media_id eq 100?
Ответы
Ответ 1
попробуйте этот
var ids = new [] { 100, 200, 300 } ;
var res = from m in provider.Media
from id in ids
where m.media_id == id
select m;
есть полное описание msdn при запросе DataServices.
другой подход будет
var results = provider.Media
.AddQueryOption("$filter", "media_id eq 100");
и поскольку OData не поддерживает операторы IN
, вы получите условие фильтрации, подобное этому
.AddQueryOption("$filter", "(media_id eq 100) or (media_id eq 200 ) or ...");
который можно построить с помощью цикла или linq Select
и string.Join
:
var ids = new [] { 100, 200, 300 };
var filter = string.Join(" or ", ids.Select(i=> $"(media_id eq {i})"));
var results = provider.Media.AddQueryOption("$filter", filter);
UPDATE: существует операция фильтрации field=["a","b"]
, но это означает что-то другое.
UPDATE2: В OData V4 есть лямбда-выражения any
и all
, в паре с литералом массива ["a", "b"]
они могут работать как IN
, но мне не удалось найти рабочий синтаксис на примере конечной точки v4 в OData. Org
Ответ 2
Развернувшись на vittore ответе (из которого вторая часть - правильный ответ), я написал для демонстрационного проекта нечто похожее на следующее:
var filterParams = ids.Select(id => string.Format("(media_id eq {0})", id));
var filter = string.Join(" or ", filterParams);
var results = provider.Media.AddQueryOption("$filter", filter).Execute().ToList();
Это не изящно, и вы не захотите использовать его для большого списка идентификаторов ( > ~ 60), но это будет трюк.
Ответ 3
Расширяясь по предложению MCattle, если нам нужно больше 50 или 60 идентификаторов, тогда его целесообразно делать в 2 или более параллельных вызовах и добавлять их в параллельный словарь или что-то подобное, так как мы получаем результаты от сервера. Хотя это увеличивает количество вызовов на сервер, но поскольку мы медленно переходим в облачную среду, это не должно быть большой проблемой, на мой взгляд.