Итак, вот в чем дело - в настоящее время я использую EF Core 3.1 и, скажем, у меня есть объект:
public class Entity
{
public int Id { get; set; }
public int AnotherEntityId { get; set; }
public virtual AnotherEntity AnotherEntity { get; set; }
}
Когда я получаю доступ к DbSet<Entity> Entities
обычному способу, я включаю AnotherEntity, например:
_context.Entities.Include(e => e.AnotherEntity)
И это работает. Почему бы и нет? Тогда я иду с:
_context.Entities.FromSqlRaw("SELECT * FROM Entities").Include(e => e.AnotherEntity)
И это тоже работает. Оба возвращают мне одну и ту же коллекцию объектов, объединенных с AnotherEntity. Затем я использую хранимую процедуру, которая состоит из того же запроса SELECT * FROM Entities
с именем spGetEntities:
_context.Entities.FromSqlRaw("spGetEntities")
Угадай, что? Это тоже работает. Это дает мне тот же вывод, но без присоединенного AnotherEntity, очевидно. Однако, если я пытаюсь добавить Включить, как это:
_context.Entities.FromSqlRaw("spGetEntities").Include(e => e.AnotherEntity)
Я осознаю:
FromSqlRaw или FromSqlInterpolated был вызван с несложным SQL и с запросом, составляющим по нему. Вы можете позвонить
AsEnumerable
после метода FromSqlRaw или FromSqlInterpolated для выполнения композиция на стороне клиента.
Хотя выходные данные _context.Entities.FromSqlRaw("SELECT * FROM Entities")
и _context.Entities.FromSqlRaw("spGetEntities")
идентичны.
Я не смог найти доказательств того, что могу или не могу сделать это с EF Core 3.1, но если бы кто-нибудь мог дать мне хоть какой-то намек на возможность такого подхода, было бы неплохо.
Кроме того, если есть другой способ объединения сущностей с помощью хранимой процедуры, я бы, вероятно, принял его как решение моей проблемы.
2 ответа
Короче, вы не можете этого сделать (по крайней мере, для SqlServer). Объяснение содержится в документации EF Core - Необработанные запросы SQL - Компоновка с помощью LINQ :
Компоновка с помощью LINQ требует, чтобы ваш необработанный SQL-запрос был компонуемым, поскольку EF Core будет обрабатывать предоставленный SQL как подзапрос. SQL-запросы, которые можно составить, начинаются с ключевого слова
SELECT
. Кроме того, передаваемый SQL не должен содержать символы или параметры, которые недопустимы в подзапросе, например:
- Завершающая точка с запятой
- На SQL Server - конечная подсказка уровня запроса (например,
OPTION (HASH JOIN)
)- В SQL Server предложение
ORDER BY
, которое не используется сOFFSET 0 OR TOP 100 PERCENT
в предложенииSELECT
SQL Server не позволяет составлять вызовы хранимых процедур, поэтому любая попытка применить дополнительные операторы запросов к такому вызову приведет к неверному SQL. Используйте метод
AsEnumerable
илиAsAsyncEnumerable
сразу после методовFromSqlRaw
илиFromSqlInterpolated
, чтобы убедиться, что EF Core не пытается создать композицию поверх хранимой процедуры.
Кроме того, поскольку для Include
/ ThenInclude
требуется EF Core IQueryable<>
, AsEnumerable
/ AsAsyncEnumerable
и т. Д. Это не вариант. Вам действительно нужен составной SQL, поэтому хранимые процедуры не подходят.
Однако вместо хранимых процедур вы можете использовать табличные функции (TVF) или представления базы данных, потому что они компонуются (select * from TVF(params)
или select * from db_view
).
В моем случае я конвертировал рабочий EF FromSql()
с кодом хранимой процедуры 2.1 в 3.1. Вот так:
ctx.Ledger_Accounts.FromSql("AccountSums @from, @until, @administrationId",
new SqlParameter("from", from),
new SqlParameter("until", until),
new SqlParameter("administrationId", administrationId));
Где AccountSums
- SP.
Единственное, что мне нужно было сделать, это использовать FromSqlRaw()
и добавить IgnoreQueryFilters()
, чтобы снова заработало. Вот так:
ctx.Ledger_Accounts.FromSqlRaw("AccountSums @from, @until, @administrationId",
new SqlParameter("from", from),
new SqlParameter("until", until),
new SqlParameter("administrationId", administrationId)).IgnoreQueryFilters();
Это упомянуто в комментариях, но я сначала пропустил это, поэтому включил это здесь.
Похожие вопросы
Связанные вопросы
Новые вопросы
c#
C# (произносится как «see Sharp») — это высокоуровневый мультипарадигменный язык программирования со статической типизацией, разработанный Microsoft. Код C# обычно нацелен на семейство инструментов и сред выполнения Microsoft .NET, которое включает в себя .NET, .NET Framework, .NET MAUI и Xamarin среди прочих. Используйте этот тег для ответов на вопросы о коде, написанном на C#, или о формальной спецификации C#.