countForFetchRequest и executeFetchRequest возвращают разное количество результатов.

Я обнаружил, что NSFetchRequest возвращает разные результаты для подсчета и выполнения.

У меня есть объект Product и объект Size. Продукт имеет много размеров.

У меня есть два продукта, продукт A и продукт B. Продукт A доступен только в размере 1, а продукт B доступен в размерах 1 и 2.

Учитывая NSPredicate

'ANY sizes.#size IN {"size1", "size2"}'

Я обнаружил, что он возвращает 3 для countForfetchRequest, но массив из 2 элементов, когда я выполняю запрос на выборку.

Счетчик - это неверное значение. ProductB имеет оба размера и, по-видимому, подсчитывается дважды в countForfetchRequest, но, очевидно, возвращается только один раз при вызове executeFetchRequest.

Я пытался установить setReturnsDistinctResults:YES безрезультатно.


person deanWombourne    schedule 26.10.2010    source источник
comment
Возможно ли, что у вас есть грязный контекст управляемого объекта, когда вы делаете вызов count? то есть в контексте есть временный объект, который может сбивать счет, или эти два вызова выполняются друг за другом?   -  person ImHuntingWabbits    schedule 04.11.2010
comment
Сделано встык, в том же управляемом контексте. И ошибка полностью повторяема, поэтому контекст не используется каким-либо другим потоком по ошибке и т. Д. Хотя мне нравится мысль; Я об этом не подумал!   -  person deanWombourne    schedule 04.11.2010
comment
Это интересно, я думаю, что единственное, что он делает, это сопоставляет каждый объект n раз для n значений в массиве. Таким образом, у вас есть 2 объекта, но 3 фактических #размера совпадают. Я думаю, что это было бы достаточно легко проверить, изменив отношение размеров к одному объекту и проверив результат подсчета.   -  person ImHuntingWabbits    schedule 04.11.2010
comment
Да, если я подсчитаю, где все результаты имеют отношение 1->1, он вернет правильную сумму. Меня интересует, почему количество и выполнение для одного и того же предиката были разными и как настроить запрос, чтобы они были одинаковыми :(   -  person deanWombourne    schedule 05.11.2010
comment
Мне кажется, что countForFetchRequest и executeFetchRequest имеют разные реализации. Последний использует дорогостоящую выборку, которая фактически создает и возвращает объекты. Первый просто перебирает базу данных и находит все совпадения. Думаю, тут конфликт интересов: либо быстрый, либо правильный метод подсчета. Тот, который должен просто считать, и тот, который должен отслеживать все объекты и исключать дубликаты из подсчета...   -  person Max Seelemann    schedule 05.11.2010
comment
Не могли бы вы объяснить, какой именно запрос вы выдаете? Из вашего описания (у товара много размеров) неясно (мне), есть ли у каждого товара хотя бы один размер. Если это так, то ваш предикат бесполезен, потому что тогда вы могли бы просто получить каждый продукт без предиката. В противном случае, если у товара могут быть нулевые размеры, то ваш предикат неверен и вам нужно его модифицировать.   -  person Massimo Cafaro    schedule 07.11.2010
comment
Привет Макс - ты прав, но я думал, что установка запроса на запрет дубликатов исправит это (за счет немного более медленного счета) :(   -  person deanWombourne    schedule 07.11.2010
comment
Привет, непрощенный - в моем примере проблемный продукт A имеет один размер, а продукт B - два - в моем наборе данных каждый продукт имеет хотя бы один размер.   -  person deanWombourne    schedule 07.11.2010
comment
Если у каждого товара есть хотя бы один размер, то предикат бесполезен. Вы можете просто напрямую получить объекты, принадлежащие сущности Product. Как я уже говорил, совсем другой случай будет, если некоторые из ваших продуктов могут иметь нулевые размеры.   -  person Massimo Cafaro    schedule 08.11.2010
comment
Вы упускаете суть моей проблемы - в моем реальном приложении мне нужен предикат, потому что он исключает некоторые продукты, которые я не хочу учитывать. Вопрос просто содержит простейший набор данных, который демонстрирует мою проблему, поэтому да, в этом случае предикат бесполезен, но даже с предикатом он должен возвращать тот же счетчик для вызовов методов countWith и executeRequest, что и является проблемой, которую мне нужно решить :)   -  person deanWombourne    schedule 08.11.2010
comment
Да, наверное, я упускаю суть. Это было причиной того, что вы спросили, какой запрос вы пытаетесь выдать. В вашем случае какие продукты нужно исключить? Те, которые имеют точно указанное количество размеров, скажем, 2? Мне нужно полностью понять это, чтобы помочь вам. И да, счетчики должны совпадать, но это произойдет только в том случае, если вы используете правильный предикат.   -  person Massimo Cafaro    schedule 08.11.2010
comment
Я пытаюсь подсчитать количество продуктов, у которых есть размер A ИЛИ размер B (или оба) — продукты, у которых нет размера A или размера B, должны быть исключены из набора результатов. Выполнение предиката работает отлично, а подсчет с тем же предикатом — нет.   -  person deanWombourne    schedule 09.11.2010


Ответы (2)


Я немного изменил предикат в ответе. Обратите внимание, что те же соображения относительно проблем синтаксического анализа, с которыми вы можете столкнуться (приведенные в одном из моих предыдущих комментариев), по-прежнему применимы. Я предполагаю, что у вас есть несколько размеров, скажем, sizeA, sizeB, sizeC и т. д. Вам нужен подзапрос для правильной обработки вашего отношения ко многим в Core Data, как показано в следующем предикате.

РЕДАКТИРОВАТЬ:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(sizes.@count == 1 || sizes.@count == 2) && (1 == SUBQUERY(sizes, $sub, $sub.#size == %@ || $sub.#size == %@).@count  || 2 == SUBQUERY(sizes, $sub, $sub.#size == %@ || $sub.#size == %@).@count)", yourSizeAvariable, yourSizeBvariable];

Дайте мне знать, если это работает правильно для вас.

person Massimo Cafaro    schedule 09.11.2010
comment
У меня две проблемы - во-первых, я постоянно получаю ошибку Невозможно разобрать строку формата независимо от того, что я пытаюсь сделать. Во-вторых, я не понимаю, как это поможет моему запросу - этот подзапрос вернет набор размеров - как мне протестировать свой продукт на этом наборе - я действительно хочу, чтобы исключение было немного ожидаемым, чтобы помочь мне отладить еще немного: ( - person deanWombourne; 09.11.2010
comment
Запрос, запущенный для объекта Product, должен возвращать все продукты, имеющие размер A или размер B (или оба). Проблема синтаксического анализа может быть связана с использованием символа # для экранирования ключевого слова размера, зарезервированного в Core Data. Попробуйте без #, но я думаю, что это не сработает. Если возможно, попробуйте изменить атрибут размера на что-то другое, например размер, а затем соответствующим образом измените предикат, удалив символ #. - person Massimo Cafaro; 10.11.2010
comment
Что касается вашего беспокойства, я не вижу, как это поможет моему запросу - этот подзапрос вернет набор размеров - как мне протестировать свой продукт на этом наборе: это неправильно. Помните, что вы выполняете запрос для объекта Product, поэтому вы всегда получаете продукты, а не размеры: вы возвращаете продукты, набор размеров которых точно соответствует указанному вами. Однако, чтобы упростить это, новый предикат теперь проверяет количество, возвращая продукты, соответствующие количеству. - person Massimo Cafaro; 10.11.2010
comment
Привет, я решил это по дороге домой - было поздно, и я был идиотом! Формат нуждался в .@count в конце - я просто получал подзапрос, а затем не проверял его ни на чем! Теперь работает на 100%, спасибо! - person deanWombourne; 10.11.2010

Я думаю, что когда вы делаете подсчет, он подсчитывает количество строк, возвращаемых из запроса sql. Когда вы запрашиваете таблицу размеров, вы возвращаете 3, потому что эквивалентный sql вернет 3 строки.

Когда вы выполняете выборку, вы получаете 2, потому что вы получите только два объекта продукта. Однако, если вы заглянете внутрь этих продуктов на количество объектов размера, вы найдете 3.

О, и выбор отдельных не будет работать, потому что у вас есть 3 уникальных набора значений :-)

person drekka    schedule 10.11.2010
comment
Да, вы абсолютно правы - оказывается, мне нужен подзапрос, чтобы удалить это :( Я просто предположил (ошибочно), что они вернут одно и то же число - @unforgiven указал мне на правильный путь :) Спасибо. - person deanWombourne; 10.11.2010