Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

combine join with String.Contains in Linq query

i have the following linq query that create a left join between two tables:

            var joinResultRows = from leftTable in dataSet.Tables[leftTableName].AsEnumerable()
                             join
                                  rightTable in dataSet.Tables[rightTableName].AsEnumerable()
                                    on leftTable.Field<string>(leftComparedColumnName) equals rightTable.Field<string>(rightComparedColumnName)
                                        into leftJoinedResult
                             select new { leftTable, leftJoinedResult };

i want to get the rows that answer this: the String value in the left column contains the string value in the right column.

i tried this :

            var joinResultRows = from leftTable in dataSet.Tables[leftTableName].AsEnumerable()
                             join
                                  rightTable in dataSet.Tables[rightTableName].AsEnumerable()
                                    on leftTable.Field<string>(leftComparedColumnName).Contains(rightTable.Field<string>(rightComparedColumnName)) equals true
                                        into leftJoinedResult
                             select new { leftTable, leftJoinedResult };

but it doesn't work cause rightTable isn't recognized in the left side of the join.

How do i create a join that results the String.Contains, do i do the contains in the 'where' clause or in the 'On' clause?

like image 412
Rodniko Avatar asked Feb 28 '23 08:02

Rodniko


2 Answers

Have you tried a SelectMany?

var result =
 from left in dataSet.Tables[leftTableName].AsEnumerable()
 from right in dataSet.Tables[rightTableName].AsEnumerable()
 where left.Field<string>(leftComparedColumnName).Contains(right.Field<string>(rightComparedColumnName))
 select new { left, right };

Edit:

The following should have the desired effect:

class ContainsEqualityComparer: IEqualityComparer<string>
{
    public bool Equals(string right, string left) { return left.Contains(right); }
    public int GetHashCode(string obj) { return 0; }
}

var result =
    dataSet.Tables[leftTableName].AsEnumerable().GroupJoin(
        dataSet.Tables[rightTableName].AsEnumerable(),
        left => left,
        right => right,
        (left, leftJoinedResult) => new { left = left, leftJoinedResult = leftJoinedResult },
        new ContainsEqualityComparer());

The key comparison is run through the custom IEqualityComparer. Two rows will only be joined when GetHashCode() of left and right are the same, and Equals returns true.

Hope it helps.

like image 169
Yannick Motton Avatar answered Mar 10 '23 23:03

Yannick Motton


I solved it by creating SelectMany (join) that the left table holds all records and the right holds null if there is no match:

var joinResultRows = from leftDataRow in dataSet.Tables[leftTableName].AsEnumerable()
                             from rightDataRow in dataSet.Tables[rightTableName].AsEnumerable()
                             .Where(rightRow => 
                                 {
                                     // Dont include "" string in the Contains, because "" is always contained
                                     // in any string.                                         
                                     if ( String.IsNullOrEmpty(rightRow.Field<string>(rightComparedColumnName)))
                                         return false;

                                     return leftDataRow.Field<string>(leftComparedColumnName).Contains(rightRow.Field<string>(rightComparedColumnName));

                                 }).DefaultIfEmpty() // Makes the right table nulls row or the match row
                              select new { leftDataRow, rightDataRow };

Thank you for the tip :)

like image 44
Rodniko Avatar answered Mar 10 '23 23:03

Rodniko