Извлечение строк из фрейма данных при определенных условиях

Шаблон репозитория представляет собой абстракцию . Цель состоит в том, чтобы уменьшить сложность и сделать остальной код неустойчивым. В качестве бонуса вы можете написать тесты unit вместо тестов integration .

Проблема в том, что многие разработчики не понимают цель шаблонов и создают репозитории, которые вызывают утечку конкретной информации до вызывающего абонента (как правило, выставляя IQueryable). Поступая таким образом, они не получают никакой пользы от использования OR / M напрямую.

Обновить для ответа на другой ответ

Кодирование исключения

Использование репозиториев не о возможность переключения технологии сохранения (т. е. изменение базы данных или использование webservice и т. д.). Речь идет об отделении бизнес-логики от настойчивости, чтобы уменьшить сложность и взаимодействие.

Тестирование модулей против тестов интеграции

Вы не пишете модульные тесты для репозиториев. период.

Но, вводя репозитории (или любой другой уровень абстракции между устойчивостью и бизнесом), вы можете писать модульные тесты для бизнес-логики. т. е. вам не нужно беспокоиться о том, что ваши тесты не выполняются из-за неправильно настроенной базы данных.

Что касается запросов. Если вы используете LINQ, вам также необходимо убедиться, что ваши запросы работают так же, как и с репозиториями. и это делается с помощью тестов интеграции.

Разница в том, что если вы не смешивали свою бизнес с операторами LINQ, вы можете быть на 100% уверены, что это ваш код настойчивости, который терпит неудачу, а не что-то еще.

Если вы проанализируете свои тесты, вы также увидите, что они намного чище, если у вас нет смешанных проблем (например, LINQ + Business logic)

Примеры репозитория

Большинство примеров это дерьмо. Это очень верно. Однако, если у вас есть какой-либо шаблон дизайна, вы найдете множество дерьмовых примеров. Это не повод избежать использования шаблона.

Создание правильной реализации репозитория очень просто. Фактически, вы должны следовать только одному правилу:

Не добавляйте ничего в класс репозитория до самого момента, когда вам это нужно

A много кодеров ленивы и пытается создать общий репозиторий и использовать базовый класс с множеством методов, которые они могли бы нуждаться. YAGNI. Вы пишете класс хранилища один раз и сохраняете его до тех пор, пока приложение живет (может быть лет). Зачем трахать его, ленив. Держите его в чистоте без наследования базового класса. Это облегчит чтение и поддержку.

(Вышеуказанное утверждение является ориентиром, а не законом. Базовый класс может быть очень мотивирован. Подумайте, прежде чем добавлять его, чтобы добавить его по правильным причинам)

Старый материал

Вывод:

Если вы не возражаете, если в своем бизнес-коде не указаны заявления LINQ и не заботитесь об модульных тестах, я не вижу причин для не использовать Entity Framework напрямую.

Обновить

Я написал как о шаблоне репозитория, так и о том, что на самом деле означает «абстракция»: http://blog.gauffin.org / 2013/01 / repository-pattern-done-right /

Обновление 2

Для одного типа сущности с 20 + полями, как вы будете создавать запрос метод поддержки любой комбинации перестановок? Вы не хотите ограничивать поиск только по имени, как насчет поиска с навигационными свойствами, перечислить все заказы с элементом с конкретным ценовым кодом, 3 уровня поиска навигационной собственности. Вся причина IQueryable была изобретена в том, чтобы иметь возможность составлять любую комбинацию поиска по базе данных. Все выглядит великолепно в теории, но потребность пользователя выигрывает выше теории.

blockquote>

Опять же: объект с 20 + полями неправильно смоделирован. Это объект БОГА. Сломай.

Я не утверждаю, что IQueryable не был сделан для запроса. Я говорю, что это неправильно для слоя абстракции, такого как шаблон репозитория , поскольку он протекает. Нет ни одного 100% -ного провайдера LINQ To Sql (например, EF).

У всех есть конкретные вещи, связанные с реализацией, например, как использовать нетерпеливую / ленивую загрузку или как выполнять SQL-запросы «IN». Выставление IQueryable в репозитории заставляет пользователя знать все эти вещи. Таким образом, вся попытка абстрагировать источник данных - это полный сбой. Вы просто добавляете сложность, не получая никакой пользы от использования OR / M напрямую.

Либо правильно создавайте шаблон хранилища, либо просто не используйте его вообще.

(if вы действительно хотите обрабатывать большие объекты, вы можете комбинировать шаблон репозитория с шаблоном Specification . Это дает вам полную абстракцию, которая также может быть проверкой.)

2
задан Ronak Shah 17 January 2019 в 11:14
поделиться

4 ответа

Мы можем использовать %in% - filter строки после группировки по 'sentId` и' partner. '

library(dplyr)
df1 %>%
  group_by(sentId., partner.) %>%
  filter(3 %in% label.)
# A tibble: 3 x 5
# Groups:   sentId. [2]
#  sentId.    B. label. partner.  code
#    <dbl> <dbl>  <dbl>    <dbl> <int>
#1       1     2      3        4   123
#2       1     2      2        4   124
#3       4     2      3        8   125

Или в компактном виде с data.table [1110 ]

library(data.table)
setDT(df1)[, .SD[3 %in% label.], .(sentId., partner.)]
<час>

Или с base R

df1[with(df1, ave(label.==3, sentId., partner., FUN = any)),]

данными

df1 <- structure(list(sentId. = c(1, 1, 4, 7), B. = c(2, 2, 2, 3), label. = c(3, 
 2, 3, 2), partner. = c(4, 4, 8, 7), code = 123:126),
 class = "data.frame", row.names = c(NA, 
 -4L))
0
ответ дан akrun 17 January 2019 в 11:14
поделиться

Использование sqldf: извлекает sentID и partner с меткой 3 как два внутренних запроса и извлекает результат из него.

names(df) <- gsub("\\.", "", names(df)) # to remove . from column name
sqldf("select * from df where (sentID IN (select sentID from df where label IS 3) OR 
      partner IN (select partner from df where label IS 3))")

Выход:

  sentId B label partner code
1      1 2     3       4  123
2      1 2     2       4  124
3      4 2     3       8  125
0
ответ дан Saurabh Chauhan 17 January 2019 в 11:14
поделиться

Эта проблема может быть легко сформулирована с использованием SQL, поэтому одним из вариантов будет использование библиотеки sqldf:

library(sqldf)

# your data frame df
sql <- "SELECT t1.\"sentId.\", t1.\"B.\", t1.\"label.\", t1.\"partner.\", t1.code
        FROM yourTable t1
        WHERE t1.\"label.\" = '3.' OR
            EXISTS (SELECT 1 FROM yourTable t2
                    WHERE t1.\"sentId.\" = t2.\"sentId.\" AND
                          t1.\"partner.\" = t2.\"partner.\" AND
                          t2.\"label.\" = '3.')"

result <- sqldf(sql)

enter image description here

[ 118]

Демонстрация

Примечание. В приведенной выше демонстрации фактически используется MariaDB, поскольку SQLite не работал с демонстрационным инструментом. Но это все еще показывает, что логика запроса верна.

0
ответ дан Tim Biegeleisen 17 January 2019 в 11:14
поделиться

Сначала мы можем найти индексы строк, в которых у нас есть интересующее значение label, а затем использовать эти индексы для подмножества значений sentId и partner из всего кадра данных.

label_value <- 3
inds <- df$label == label_value
df[with(df, sentId %in% sentId[inds] & partner %in% partner[inds]), ]

#  sentId B label partner code
#1      1 2     3       4  123
#2      1 2     2       4  124
#3      4 2     3       8  125

Та же логика в dplyr будет

library(dplyr)

df %>%
  filter(sentId %in% sentId[label == label_value] & 
         partner %in% partner[label == label_value])
0
ответ дан Ronak Shah 17 January 2019 в 11:14
поделиться
Другие вопросы по тегам:

Похожие вопросы: