Entity Framework проектируемый столбец - PullRequest
0 голосов
/ 04 октября 2018

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

У меня есть свойство на моей сущности как MaterialId, но оно состоит из MATERIAL + MATERIAL_GRP_1

, есть ли способ сделать это в EF .netcore2.1

Я пытался использовать

entity.Property(p => p.MaterialId).HasComputedColumnSql("[MATERIAL] + '-' + [MATERIAL_GROUP_1]");

, однако, когда я запрашиваю эту сущность, сгенерированный SQL в базе данных ищет $it.MaterialIdчто не удается, поскольку в таблице базы данных нет такого столбца.

Есть ли способ решить эту проблему?

Ответы [ 2 ]

0 голосов
/ 04 октября 2018

Итак, у вас есть последовательность entities, где каждый entity имеет некоторые свойства.Вы хотите выбрать несколько (или все) элементы из этой последовательности и преобразовать каждый entity в объект аналогичного класса.Для этого мы используем Select

Я не уверен, что ваша последовательность AsEnumerable или AsQueryable.Разница в том, что IQueryable должен выполняться в другом процессе, обычно в базе данных, тогда как IEnumerable должен выполняться в вашем локальном процессе.

AsEnumerable

Давайте сначалаопишите IEnumerable.Предположим, что ваша входная последовательность является последовательностью Persons, а ваш выходной - SimplePersons.Хотя они выглядят одинаково, есть небольшая разница

class Person
{
    public int Id {get; set;}
    public string FirstName {get; set;}
    public string LastName {get; set;}
}
class SimplePerson
{
    public int Id {get; set;}
    public string FullName {get; set;}
}

Предположим, у вас есть последовательность людей, и вы хотите преобразовать их в последовательность простых людей: каждый Person должен стать одним SimplePerson, где FullName - это объединение FirstName и LastName.

Use 'Select to project every Person into a SimplePerson`:

IEnumerable<Person> persons = ...
IEnumerable<SimplePerson> simplePersons = persons
   // convert every Person into a SimplePerson:
   .Select(person => new SimplePerson()
   {
        Id = person.Id,
        FullName = person.FirstName + " " + person.LastName,
   });

Вуаля!Simple comme bonjour!

AsQueryable

Если ваша входная последовательность Persons AsQueryable, то обычно запрос должен выполняться другим процессом.Это довольно часто система управления базами данных.IQueryable имеет Expression и Provider.Expression представляет запрос, который должен быть выполнен.Provider знает, кто должен выполнить запрос (какая СУБД), он знает, как перевести Expression на язык, который исполнитель запроса (SQL), и знает, как общаться с исполнителем.

Когда нужно перечислить IQueryable, либо неявно с помощью foreach, ToList(), FirstOrDefault(), Max() и т. Д., Либо явно с использованием GetEnumerator и MoveNext, Expressionотправлено на Provider.

Provider переводит Expression на язык, который СУБД понимает и выполняет запрос.Результат преобразуется в IEnumerable, для которого GetEnumerator и MoveNext называются

Проблема состоит в том, что SQL не знает ваш SimplePerson, поэтому он не может вызвать его конструктор.

Одним из решений было бы позвонить ToList() перед тем, как проецировать Persons в SimplePersons:

IEnumerable<SimplePerson> FetchSimplePersons()
{
    IQueryable<Person> persons = ...
    IEnumerable<SimplePerson> simplePersons = simplePersons
        // execute the query, move persons to local process
        .ToList()
        // convert every Person into a SimplePerson:
        .Select(person => new SimplePerson()
        {
            Id = person.Id,
            FullName = person.FirstName + " " + person.LastName,
        });
    return simplePersons;
}

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

bool personsAvailable = FetchSimplePersons().Any()

Сначала вы выбираете все 1000 человек, а затем проверяете, есть ли хотя бы один SimplePerson.Какая трата вычислительной мощности!

Для этого изобретено AsEnumerable().Эта функция извлекает запрашиваемые данные разумным способом, поэтому, если вы не используете все извлеченные данные, потери не слишком велики.Есть несколько стратегий, чтобы ограничить потери.Фактически используемая стратегия отличается для Provider.

. Часто используемая стратегия для AsEnumerable будет заключаться в получении Persons на страницу, скажем, 100 Persons.Если вы используете только несколько из них, вы выбросите все остальные извлеченные Persons на странице, но по крайней мере это лучше, чем выбрасывать все 1000 Persons

IEnumerable<SimplePerson> FetchSimplePersons()
{
    IQueryable<Person> persons = ...
    IEnumerable<SimplePerson> simplePersons = simplePersons
        // execute the query per page:
        .AsEnumerable()

        // convert every fetched Person into a SimplePerson:
        .Select(person => new SimplePerson()
        {
            Id = person.Id,
            FullName = person.FirstName + " " + person.LastName,
        });
    return simplePersons;
}

AsEnumerable()достаточно умен, чтобы выбрать следующую страницу, если MoveNext вызывается в последнем элементе текущей страницы.Так что для пользователей это похоже на ToList ().

0 голосов
/ 04 октября 2018

Рекомендую по-другому

  public class Contact
    {

        public string MATERIAL { get; set; }
        public string MATERIAL_GROUP_1 { get; set; }

        [NotMapped]
        public string MaterialId => $"{MATERIAL} {MATERIAL_GROUP_1}";


    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...