объединить соединение с String.Contains в запросе Linq

у меня есть следующий запрос linq, который создает левое соединение между двумя таблицами:

            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 };

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

я пробовал это:

            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 };

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

Как мне создать объединение, которое приводит к String.Contains, делать ли это в предложении «где» или в предложении «Вкл.»?


person Rodniko    schedule 01.09.2009    source источник


Ответы (2)


Вы пробовали 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 };

Редактировать:

Следующее должно иметь желаемый эффект:

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());

Сравнение ключей выполняется с помощью пользовательского компаратора IEqualityComparer. Две строки будут соединены только тогда, когда GetHashCode() слева и справа одинаковы, а Equals возвращает true.

Надеюсь, поможет.

person Yannick Motton    schedule 01.09.2009
comment
+1 для SelectMany — LINQ поддерживает только эквивалентные соединения, которые связывают элементы в последовательностях по равенству ключей. - person dahlbyk; 02.09.2009
comment
selectMany - это то, о чем я не подумал, спасибо. он находит совпадения, но не решает мою проблему, потому что мне нужно ЛЕВОЕ СОЕДИНЕНИЕ, которое создает новую объединенную таблицу или, по крайней мере, анонимный тип, который имеет две таблицы - левую и присоединяемую (как в моем примере выше). после выполнения моего запроса выше я построил таблицу результатов вручную, используя как leftTable,leftJoinedResult. Могу ли я сделать SelectMany левым соединением? - person Rodniko; 02.09.2009
comment
Я считаю, что нет реального способа добиться того, что вы пытаетесь сделать с помощью LinQ и анонимных типов. Однако есть несколько обходных путей, я постараюсь помочь вам в этом посте. - person Yannick Motton; 03.09.2009
comment
Я изучил это немного подробнее и воспроизвел желаемый эффект с помощью GroupJoin, перегружая IEqualityComparer. - person Yannick Motton; 03.09.2009

Я решил это, создав SelectMany (объединение), чтобы левая таблица содержала все записи, а правая содержала нуль, если совпадения нет:

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 };

Спасибо за совет :)

person Rodniko    schedule 09.09.2009