LINQ - «Не удалось перевести выражение» с ранее использованным и проверенным условием запроса - PullRequest
5 голосов
/ 26 ноября 2011

Я довольно новичок в LINQ и не могу понять некоторые противоречия в поведении. Любой знающий вклад будет высоко ценится. Я вижу похожие проблемы в SO и в других местах, но, похоже, они не помогают.

У меня очень простая настройка - таблица компании и таблица адресов. У каждой компании может быть 0 или более адресов, и если> 0, один должен быть указан в качестве основного адреса. Я пытаюсь обработать случаи, когда есть 0 адресов, используя внешнее соединение и соответственно изменяя оператор выбора.

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

Следующие ДЕЛАЕТ РАБОТАЕТ

IQueryable query =
    from comp in context.Companies
    join addr in context.Addresses on comp.CompanyID equals addr.CompanyID into outer   // outer join companies to addresses table to include companies with no address
    from addr in outer.DefaultIfEmpty()
    where (addr.IsMain == null ? true : addr.IsMain) == true    // if a company has no address ensure it is not ruled out by the IsMain condition - default to true if null
    select new {
        comp.CompanyID,
        comp.Name,
        AddressID = (addr.AddressID == null ? -1 : addr.AddressID), // use -1 to represent a company that has no addresses
        MainAddress = String.Format("{0}, {1}, {2} {3} ({4})", addr.Address1, addr.City, addr.Region, addr.PostalCode, addr.Country)
    };

но при этом в GridView отображается пустой адрес как ", , ()"

Итак, я обновил поле MainAddress, чтобы оно было

MainAddress = (addr.AddressID == null ? "" : String.Format("{0}, {1}, {2} {3} ({4})", addr.Address1, addr.City, addr.Region, addr.PostalCode, addr.Country))

и теперь я получаю ошибку Could not translate expression и кучу автоматически сгенерированного кода ошибки, который для меня очень мало значит.

Условие, которое я добавил в MainAddress, ничем не отличается от рабочего условия для AddressID, поэтому кто-нибудь может сказать мне, что здесь происходит?

Любая помощь очень ценится.

1 Ответ

6 голосов
/ 26 ноября 2011

Ошибка, которую вы получаете, говорит вам, что LinqToSql не может перевести вашу пустую проверку, а затем выражение string.Format в SQL.Если вы посмотрите на SQL, который генерирует ваш первый запрос (используя LinqPad или SQL Profiler), вы увидите что-то вроде:

SELECT [t0].[CompanyID], [t0].[Name], 
    (CASE 
        WHEN [t1].[AddressID] IS NULL THEN @p0
        ELSE [t1].[AddressID]
     END) AS [AddressID], 
    [t1].[Address1] AS [value], 
    [t1].[City] AS [value2], 
    [t1].[Region] AS [value3], 
    [t1].[PostalCode] AS [value4], 
    [t1].[Country] AS [value5]
FROM [Company] AS [t0]
LEFT OUTER JOIN [Address] AS [t1] ON [t0].[CompanyID] = [t1].[CompanyID]
WHERE ([t1].[IsMain] IS NULL) OR ([t1].[IsMain] = 1)

Для вашего поля AddressID вы увидите, что оно используетCASE-WHEN для обработки условия, когда AddressID равно нулю.Когда вы добавляете CASE-WHEN для MainAddress, он пытается сделать то же самое для этого поля, но нет никакого SQL-эквивалента string.Format, который он может использовать для предложения ELSE, поэтому он взрывается.

Простой способ обойти эту проблему - использовать метод для форматирования строки.Вызывая закрытый метод, LinqToSql не будет пытаться преобразовать string.Format в SQL, а вместо этого вернет все поля, необходимые для заполнения объекта Address.Затем метод может позаботиться о форматировании.

Например:

LINQ:

....
select new {
    comp.CompanyID,
    comp.Name,
    AddressID = (addr.AddressID == null ? -1 : addr.AddressID),
    MainAddress = FormatAddress(addr)
};

Метод:

private static string FormatAddress(Address addr)
{
    return (addr == null ? "" : 
            string.Format("{0}, {1}, {2} {3} ({4})", 
                      addr.Address1, addr.City, 
                      addr.Region, addr.PostalCode, addr.Country));
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...