C# Retrieve Common Records by LINQ


December 2018


115 time


I have a database with the table that keeps user_ids and tag_ids. I want to write a function which takes two user_ids and returns the tag_ids that both users have in common.

These are the sample rows from the database:

   User_id     Tag_id
     1          100
     1          101
     2          100
     3          100
     3          101
     3          102

What I want from my function is that when I call my function like getCommonTagIDs(1, 3), it should return (100,101). What I did so far is that I keep the rows which are related to user_id in two different lists and then using for loops, return the common tag_ids.

 using (TwitterDataContext database = TwitterDataContext.CreateTwitterDataContextWithNoLock())

            IEnumerable<Usr_Tag> tags_1 = database.Usr_Tags.Where(u => u.User_id == userID1).ToList();
            IEnumerable<Usr_Tag> tags_2 = database.Usr_Tags.Where(u => u.User_id == userID2).ToList();

            foreach (var x in tags_1)
                foreach (var y in tags_2) {
                    if (x.Tag_id == y.Tag_id) {
                        var a =database.Hashtags.Where(u => u.Tag_id==x.Tag_id).SingleOrDefault();


What I want to ask is that, instead of getting all rows from database and searching for the common tag_ids in the function, I want to get the common tag_ids directly from database with LINQ by making the calculations on the database side. I would be grateful if you could help me.

This is the SQL that I wrote:

 SELECT [Tag_id]
 FROM [BitirME].[dbo].[User_Tag]
 WHERE USER_ID = '1'  AND Tag_id IN (
 SELECT [Tag_id]
 FROM [BitirME].[dbo].[User_Tag]
 where USER_ID = '3')

3 answers


Вот один из способов сделать это:

int[] users = new int[] {1,3};  // for testing

database.Ustr_Tags.Where(t => users.Contains(t.User_id))
                  .GroupBy(t => t.Tag_id)
                  .Where(g => users.All(u => g.Any(gg=>gg.User_id == u)))  // all tags where all required users are tagged
                  .Select(g => g.Key);

Одним из преимуществ этого является один он может быть использован для любого количества пользователей (а не только 2).


То, что вы хотите, это «пересечение» этих двух множеств:

var commonTags = database.Usr_Tags.Where(u => u.User_id == userID1).Select(u => u.Tag_id)
    .Intersect(database.Usr_Tags.Where(u => u.User_id == userID2).Select(u => u.Tag_id));

И вуаля, вы сделали.

Или, чтобы очистить его немного:

public static IQueryable<int> GetUserTags(int userId)
    return database.Usr_Tags
        .Where(u => u.User_id == userId)
        .Select(u => u.Tag_id);

var commonTags = GetUserTags(userID1).Intersect(GetUserTags(userID2));

Если я получил это право, запрос, как это может быть, что вам нужно

var q = from t in database.Usr_Tags
        //all Usr_Tags for UserID1
        where t.User_Id == userID1 &&
        //and there is a User_tag for User_ID2 with same Tag_ID
        database.User_Tags.Any(t2=>t2.User_ID==userID2 && t2.Tag_ID==t.Tag_ID)
        select t.Tag_Id;

var commonTags = q.ToList();