Entity framework запросы к базе
LINQ to Entities позволяет создавать запросы к источнику данных. Однако в случае, если запрос очень сложный по своей структуре или нам его легче описать на языке SQL, то в Entity Framework Core выполнить напрямую sql-запрос.
FromSqlRaw
Для получения данных из БД у объектов DbSet определен метод FromSqlRaw() , который принимает в качестве параметра sql-выражение и набор параметров. В качестве результата FromSqlRaw возвращает набор полученных из бд объектов.
При этом надо учитывать, что передаваемое в метод FromSqlRaw SQL-выражение не должно извлекать связанные данные, а полученные значения должны соответствовать определению какого-либо класса.
Для примера возьмем следующие модели и контекст данных:
Пусть ранее у нас были добавлены следующие данные:
Например, получим все объекты из таблицы Companies:
Выражение SELECT извлекает данные из таблицы. Так как эта таблица сопоставляется с моделью Company и хранит объекты этой модели, то в результате мы получим набор объектов класса Company.
При этом мы можем добавлять к методу другие методы LINQ, которые все вместе будут конкатенироваться в одно общее SQL-выражение:
В итоге будет выполняться следующее SQL-выражение:
Также можно использовать метод Include для подгрузки связанных данных:
Поиск сущности по первичному ключу
В коде ниже приведено несколько примеров использования метода Find.
Срок действия запроса
Ниже приведено общее описание процесса, через который проходит каждый запрос.
- LINQ-запрос обрабатывается Entity Framework Core для создания представления, которое готово для обработки поставщиком данных.
- Результат кэшируется, чтобы не выполнять эту обработку каждый раз при выполнении запроса.
- Поставщик базы данных определяет, какие части запроса могут выполняться в базе данных.
- Эти части запроса преобразуются в язык запроса базы данных (например, SQL для реляционной базы данных).
- Запрос отправляется в базу данных, и возвращается результирующий набор (результатами являются значения из базы данных, а не экземпляры сущностей)
- Если запрос является запросом отслеживания, EF проверяет, не предоставляют ли данные сущность, которая уже находится в объекте отслеживания изменений для экземпляра контекста.
- Если да, возвращается имеющаяся сущность.
- Если нет, создается другая сущность, устанавливается объект отслеживания изменений и возвращается новая сущность.
- Если запрос не является отслеживаемым запросом, то всегда создается и возвращается новая сущность.
Finding entities using primary keys
The Find method on DbSet uses the primary key value to attempt to find an entity tracked by the context. If the entity is not found in the context then a query will be sent to the database to find the entity there. Null is returned if the entity is not found in the context or in the database.
Find is different from using a query in two significant ways:
- A round-trip to the database will only be made if the entity with the given key is not found in the context.
- Find will return entities that are in the Added state. That is, Find will return entities that have been added to the context but have not yet been saved to the database.
Finding an entity by composite primary key
Entity Framework allows your entities to have composite keys - that's a key that is made up of more than one property. For example, you could have a BlogSettings entity that represents a users settings for a particular blog. Because a user would only ever have one BlogSettings for each blog you could chose to make the primary key of BlogSettings a combination of BlogId and Username. The following code attempts to find the BlogSettings with BlogId = 3 and Username = "johndoe1987":
Note that when you have composite keys you need to use ColumnAttribute or the fluent API to specify an ordering for the properties of the composite key. The call to Find must use this order when specifying the values that form the key.
В этом разделе рассматриваются различные способы запроса данных с помощью Entity Framework, включая LINQ и метод Find. Методы, представленные в этом разделе, также применимы к моделям, созданным с помощью Code First и конструктора EF.
Когда выполняются запросы
При вызове операторов LINQ вы просто создаете представление запроса в памяти. Запрос отправляется в базу данных только после обработки результатов.
Ниже приведены наиболее распространенные операции, которые приводят к отправке запроса в базу данных.
- Итерация результатов в цикле for .
- Использование операторов, таких как ToList , ToArray , Single , Count , или эквивалентных асинхронных перегрузок
Всегда проверяйте входные данные пользователя. Так как платформа EF Core с помощью параметров и экранирования литералов в запросах обеспечивает защиту от атак путем внедрения кода SQL, она не проверяет входные данные. Поэтому необходимо выполнять проверку в соответствии с требованиями отдельного приложения, прежде чем значения из непроверенных источников будут использоваться в LINQ-запросах, назначенные свойствам сущности или передаваемые другим API EF Core. Сюда входят все входные данные пользователя, используемые для динамического формирования запросов. Даже при использовании LINQ, если вы принимаете входные данные пользователя для создания выражений, необходимо убедиться, что можно создать только предполагаемые выражения.
Кроме использования инфраструктуры LINQ to Entities для создания запросов Entity Framework Core также позволяет писать запросы к базе данных сразу на языке SQL. Это может быть удобно, если запрос очень сложный по своей структуре или если Entity Framework Core на основе Linq to Entities создает не очень оптимальный sql-запрос.
ExecuteSqlRaw
Метод FromSqlRaw() осуществляет выборку из БД, но кроме выборки нам, возможно, придется удалять, обновлять уже существующие или вставлять новые записи. Для этой цели применяется метод ExecuteSqlRaw() и его асинхронная версия - ExecuteSqlRawAsync() , которые возвращают количество затронутых командой строк. Для его вызова у контекста данных используется свойство Database :
Интерполяция строк
Для методов FromSqlRaw и ExecuteSqlRaw в EF Core определены их двойники - методы FromSqlInterpolated() и ExecuteSqlInterpolated() (асинхронная версия - ExecuteSqlInterpolatedAsync() ), которые позволяют использовать интерполяцию строк для передачи параметров. Пример с FromSqlInterpolated :
В этом случае на стороне сервера также будут создаваться параметры для передачи значений name и age наподобие:
FromSqlRaw
Для получения данных из БД у объектов DbSet определен метод FromSqlRaw() , который принимает в качестве параметра sql-выражение и набор параметров. В качестве результата FromSqlRaw возвращает набор полученных из бд объектов.
При этом надо учитывать, что передаваемое в метод FromSqlRaw SQL-выражение не должно извлекать связанные данные, а полученные значения должны соответствовать определению какого-либо класса.
Для примера возьмем следующие модели и контекст данных:
Пусть ранее у нас были добавлены следующие данные:
Например, получим все объекты из таблицы Companies:
Выражение SELECT извлекает данные из таблицы. Так как эта таблица сопоставляется с моделью Company и хранит объекты этой модели, то в результате мы получим набор объектов класса Company.
При этом мы можем добавлять к методу другие методы LINQ, которые все вместе будут конкатенироваться в одно общее SQL-выражение:
В итоге будет выполняться следующее SQL-выражение:
Также можно использовать метод Include для подгрузки связанных данных:
Поиск сущности по составному первичному ключу
Платформа Entity Framework позволяет сущностям иметь составные ключи, то есть ключи, состоящие из нескольких свойств. Например, вы можете создать сущность BlogSettings, которая представляет собой параметры пользователей для конкретного блога. Так как пользователю необходима только одна сущность BlogSettings для каждого блога, первичный ключ для BlogSettings может состоять из комбинации идентификатора блога и имени пользователя. Следующий код пытается найти BlogSettings по идентификатору = 3 и имени пользователя = johndoe1987:
Если у вас есть составные ключи, вам нужно использовать ColumnAttribute или текучий API, чтобы указать порядок свойств составного ключа. В вызове метода Find эти значения ключа должны указываться в том же порядке.
Эта статья устарела, и некоторые ее части необходимо обновить с учетом изменений, внесенных при создании конвейера запросов. Если у вас есть какие-либо сомнения о поведении, описанном здесь, задайте вопрос.
Finding an entity by primary key
The following code shows some uses of Find:
Finding entities using a query
DbSet and IDbSet implement IQueryable and so can be used as the starting point for writing a LINQ query against the database. This is not the appropriate place for an in-depth discussion of LINQ, but here are a couple of simple examples:
Note that DbSet and IDbSet always create queries against the database and will always involve a round trip to the database even if the entities returned already exist in the context. A query is executed against the database when:
When results are returned from the database, objects that do not exist in the context are attached to the context. If an object is already in the context, the existing object is returned (the current and original values of the object's properties in the entry are not overwritten with database values).
When you perform a query, entities that have been added to the context but have not yet been saved to the database are not returned as part of the result set. To get the data that is in the context, see Local Data.
If a query returns no rows from the database, the result will be an empty collection, rather than null.
Асинхронные версии
Методы Database.ExecuteSqlInterpolated() и Database.ExecuteSqlRaw имеют асинхронные версии:
This topic covers the various ways you can query for data using Entity Framework, including LINQ and the Find method. The techniques shown in this topic apply equally to models created with Code First and the EF Designer.
FromSqlRaw
Для получения данных из БД у объектов DbSet определен метод FromSqlRaw() , который принимает в качестве параметра sql-выражение и набор параметров. В качестве результата FromSqlRaw возвращает набор полученных из бд объектов.
При этом надо учитывать, что передаваемое в метод FromSqlRaw SQL-выражение не должно извлекать связанные данные, а полученные значения должны соответствовать определению какого-либо класса.
Для примера возьмем следующие модели и контекст данных:
Пусть ранее у нас были добавлены следующие данные:
Например, получим все объекты из таблицы Companies:
Выражение SELECT извлекает данные из таблицы. Так как эта таблица сопоставляется с моделью Company и хранит объекты этой модели, то в результате мы получим набор объектов класса Company.
При этом мы можем добавлять к методу другие методы LINQ, которые все вместе будут конкатенироваться в одно общее SQL-выражение:
В итоге будет выполняться следующее SQL-выражение:
Также можно использовать метод Include для подгрузки связанных данных:
ExecuteSqlRaw
Метод FromSqlRaw() осуществляет выборку из БД, но кроме выборки нам, возможно, придется удалять, обновлять уже существующие или вставлять новые записи. Для этой цели применяется метод ExecuteSqlRaw() , который возвращает количество затронутых командой строк. Для его вызова у контекста данных используется свойство Database :
Поиск сущностей с помощью первичных ключей
Метод Find в классе DbSet использует значение первичного ключа, чтобы найти сущность, отслеживаемую контекстом. Если сущность не найдена в контексте, запрос отправляется в базу данных для поиска сущности там. Если сущность не найдена в контексте или в базе данных, возвращается значение NULL.
Метод Find имеет два важных отличия от запроса:
- Круговой путь к базе данных будет использоваться только в том случае, если сущность с указанным ключом не найдена в контексте.
- Метод Find возвращает сущности в состоянии "Добавлено". Это значит, что метод Find возвращает сущности, которые были добавлены в контекст, но еще не были сохранены в базе данных.
Параметры
Другая версия метода FromSqlRaw() позволяет использовать параметры. Например, выберем из бд все модели, в названии которых есть подстрока "Tom":
Поскольку выше приведенный контекст данных подключается к бд SQLite, то для представления параметров применяется тип SqliteParameter из пространства имен Microsoft.Data.Sqlite . Конструктор SqliteParameter имеет ряд версий. В данном случае в конструктор передается два параметра. Первый параметр - название параметра, через который на него можно ссылаться в строке запроса - в данном случае "@name". Второй параметр - значение параметра.
Если бы подключение шло к бд MS SQL Server, то для представления параметров применялся бы класс SqlParameter из пространства имен Microsoft.Data.SqlClient :
Также мы можем определять параметры как простые переменные:
Параметры
Другая версия метода FromSqlRaw() позволяет использовать параметры. Например, выберем из бд все модели, в названии которых есть подстрока "Tom":
Класс SqlParameter из пространства имен System.Data.SqlClient позволяет задать параметр, который затем передается в запрос sql.
Также мы можем определять параметры как простые переменные:
Поиск сущностей с помощью запроса
DbSet и IDbSet реализуют IQueryable, поэтому их можно использовать как начальную точку для написания запроса LINQ к базе данных. Здесь мы не будем подробно рассматривать LINQ, но приведем несколько простых примеров:
Обратите внимание, что DbSet и IDbSet всегда создают запросы к базе данных и всегда используют круговой путь к базе данных, даже если возвращаемые сущности уже присутствуют в контексте. Запрос выполняется в базе данных, если:
Когда из базы данных возвращаются результаты, объекты, отсутствующие в контексте, присоединяются к контексту. Если объект уже есть в контексте, возвращается существующий объект (текущие и исходные значения свойств объекта в записи не переписываются значениями из базы данных).
Когда вы выполняете запрос, сущности, которые были добавлены в контекст, но еще не были сохранены в базе данных, не возвращаются в составе результирующего набора. Чтобы получить данные из контекста, см. раздел Локальные данные.
Если запрос не возвращает строки из базы данных, результатом будет пустая коллекция, а не NULL.
Интерполяция строк
Для методов FromSqlRaw и ExecuteSqlRaw в EF Core определены их двойники - методы FromSqlInterpolated() и ExecuteSqlInterpolated() соответственно, которые позволяют использовать интерполяцию строк для передачи параметров. Пример с FromSqlInterpolated :
В этом случае на стороне сервера также будут создаваться параметры для передачи значений name и age наподобие:
Читайте также: