SQL запрос, включая Contains () и group, не работает должным образом - PullRequest
1 голос
/ 28 апреля 2020

У меня есть следующий случай:

  • идентификаторы категории пользователя x в таблице UserInterests: 1, 2, 3
  • идентификаторы категории пользователя y в таблице UserInterests: 1, 2

Идентификаторы категорий являются целочисленными значениями, где (ApplicationUserId, CategoryId) является составным первичным ключом упомянутой таблицы. Это форма записей:

userx 1

userx 2

userx 3

usery 1

usery 2

string Interest = "1 2"

Я хочу выполнить SQL запрос, который позволил бы мне получать только пользователей с 1 и 2 в качестве интересов (не пользователь x).

Когда я выполняю запрос, показанный ниже (зная, что переменная результата содержит идентификаторы моих пользователей), я продолжаю получать user x и user y; Я предполагаю, что он получает пользователей, содержащих 1 и 2, но я не хочу, чтобы пользователь x в результате.

int count = 2

var result2 = (from t8 in result
               from t9 in _dbContext.UserInterests
               where  t8.id == t9.ApplicationUserId && interests.Contains(t9.CategoryId.ToString())
               group t8 by t8.id into g
               where g.Count() == count
               select g.Key).ToList();

Любая помощь приветствуется!

Ответы [ 2 ]

0 голосов
/ 30 апреля 2020

Есть несколько способов добиться того, чего вы хотите, исходя из того, что вы уже убрали пользователей из БД. Учитывая это, я не знаю ни одного метода для достижения этого с одним запросом БД.

Я создал простой пример для проверки результата запроса, но вы можете заменить переменные на свои.

Решение 1 - Не рекомендуется

    static void Main(string[] args)
    {
        // Sample Data
        var allUsers = new List<User>
        {
            new User{Id = 1, Name = "User X"},
            new User{Id = 2, Name = "User Y"},
            new User{Id = 3, Name = "User Z"},
            new User{Id = 4, Name = "User W"}
        };

        var userInterests = new List<UserInterest>
        {
            new UserInterest {FakeId = 1, UserId = 1, CategoryId = 1},
            new UserInterest {FakeId = 2,UserId = 1, CategoryId = 2},
            new UserInterest {FakeId = 3,UserId = 1, CategoryId = 3},
            new UserInterest {FakeId = 4,UserId = 2, CategoryId = 1},
            new UserInterest {FakeId = 5,UserId = 2, CategoryId = 2},
            new UserInterest {FakeId = 6,UserId = 3, CategoryId = 1},
            new UserInterest {FakeId = 7,UserId = 3, CategoryId = 4}
        };

        var interests = "1 2";
        var interestsFilter = interests.Split(" ").ToList();

        var unwantedUserIds = userInterests.Where(q => interestsFilter.All(q2 => q.CategoryId != int.Parse(q2)))
                                            .Select(q => q.UserId).Distinct();

        // Get All users ids that match the filter
        var myUserIds = userInterests.Where(q => unwantedUserIds.All(q2 => q.UserId != q2))
            .Select(q => q.UserId).Distinct();

        // Or Get the users directly 
        var myUsers = allUsers.Join(userInterests,
                                        user => user.Id,
                                        userInterest => userInterest.UserId,
                                        (user, userInterest) => user).Where(q => unwantedUserIds.All(q2 => q.Id != q2)).Distinct();

    }

Решение 2 - Необработанный Sql

Поскольку вы используете платформу сущностей и до тех пор, пока Вы можете достичь результатов с помощью одного запроса к БД, который вы go Raw Sql в случае, если Linq не смог это сделать.

Сырье Sql

0 голосов
/ 28 апреля 2020

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

from t8 in result
join t9 in _dbContext.UserInterests
on t8.id equals t9.ApplicationUserId ...

Отсутствие двух from ключевых слов и двух where ключевых слов в одном запросе должно облегчить обслуживание.


Во-вторых, я бы изменил string interests = "1 2" на массив: string[] interests = {"1", "2"}


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

Другой способ: {HasOnlyXCategories} = {AllUserCategoryPairs} - {AllUsersWithCategoriesNotInX}

Надеюсь, ясно, что этот новый запрос гораздо проще написать. Мы уже начинаем с {AllUserCategoryPairs} в нашем объединении, поэтому нам нужно написать запрос подзапроса, который выбирает тех пользователей, у которых есть категории не в interests, а затем исключает тех пользователей, которых мы находим.

Следующее должно быть Вы заканчиваете или закрываете.

var result2 = from u in result
              join c in _dbContext.UserInterests
                  on u.id equals c.ApplicationUserId
                  and !interests.Contains(c.CategoryId)
                  into usersBadCategories
              where !usersBadCategories.Any()
              select u;

Возможно, вам придется немного отрегулировать его в соответствии с вашим контекстом, но это должно быть примерно по форме.

...