LINQ to Entities не распознает систему метода.Строковый Формат (System.Строка, Система.объектная система.Объект')


У меня есть этот запрос LINQ:

private void GetReceivedInvoiceTasks(User user, List<Task> tasks)
{
    var areaIds = user.Areas.Select(x => x.AreaId).ToArray();

    var taskList = from i in _db.Invoices
                   join a in _db.Areas on i.AreaId equals a.AreaId
                   where i.Status == InvoiceStatuses.Received && areaIds.Contains(a.AreaId)
                   select new Task {
                       LinkText = string.Format(Invoice {0} has been received from {1}, i.InvoiceNumber, i.Organisation.Name),
                       Link = Views.Edit
                   };
}

у него есть проблемы, хотя. Я пытаюсь создавать задачи. Для каждой новой задачи, когда я устанавливаю текст ссылки на постоянную строку, такую как" Hello", это нормально. Однако выше я пытаюсь построить свойство linktext, используя свойства счета-фактуры.

Я получаю эту ошибку:

base {System.SystemException} = {"LINQ to Entities не распознает метод' System.Строковый Формат (System.Строка, Система.Объект, Система.Метод объекта), и этот метод не может быть переведен в магазине выражение."}

кто-нибудь знает почему? Кто-нибудь знает альтернативный способ сделать это, чтобы заставить его работать?

2 65

2 ответа:

Entity Framework пытается выполнить вашу проекцию на стороне SQL, где нет эквивалента string.Format. Используйте AsEnumerable() для принудительной оценки этой части с помощью Linq для объектов.

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

int statusReceived = (int)InvoiceStatuses.Received;
var areaIds = user.Areas.Select(x=> x.AreaId).ToArray();

var taskList = (from i in _db.Invoices
               where i.Status == statusReceived && areaIds.Contains(i.AreaId)
               select i)
               .AsEnumerable()
               .Select( x => new Task()
               {
                  LinkText = string.Format("Invoice {0} has been received from {1}", x.InvoiceNumber, x.Organisation.Name),
                  Link = Views.Edit
                });

также я вижу, что вы используете связанные сущности в запросе (Organisation.Name) убедитесь, что вы добавляете правильное Include к вашему запросу, или конкретно материализовать эти свойства для последующего использования, т. е.:

var taskList = (from i in _db.Invoices
               where i.Status == statusReceived && areaIds.Contains(i.AreaId)
               select new { i.InvoiceNumber, OrganisationName = i.Organisation.Name})
               .AsEnumerable()
               .Select( x => new Task()
               {
                  LinkText = string.Format("Invoice {0} has been received from {1}", x.InvoiceNumber, x.OrganisationName),
                  Link = Views.Edit
                });

IQueriable происходит от IEnumerable, основное сходство заключается в том, что когда вы делаете свой запрос, он отправляется в компонент database engine на своем языке, тонкий момент-это когда вы говорите C# обрабатывать данные на сервере(а не на стороне клиента) или говорить SQL обрабатывать данные.

Так что в основном, когда вы говорите IEnumerable.ToString (), C# получает сбор данных и вызывает ToString () для объекта. Но когда вы говорите IQueriable.ToString () C# говорит SQL, чтобы вызвать ToString () на объекте, но там нет такого метода в SQL.

недостаток заключается в том, что при обработке данных в C# вся коллекция, которую вы ищете, должна быть создана в памяти до того, как C# применит фильтры.

наиболее эффективный способ сделать это-сделать запрос как IQueriable со всеми фильтрами, которые вы можете применить.

и затем построить его в памяти и форматирование данных в C#.

IQueryable<Customer> dataQuery = Customers.Where(c => c.ID < 100 && c.ZIP == 12345 && c.Name == "John Doe");

 var inMemCollection = dataQuery.AsEnumerable().Select(c => new
                                                  {
                                                     c.ID
                                                     c.Name,
                                                     c.ZIP,
                                                     c.DateRegisterred.ToString("dd,MMM,yyyy")
                                                   });