简体   繁体   English

MySql 上的实体框架核心调用 FromSqlInterpolated 并返回实体列表

[英]Entity Framework Core on MySql calling FromSqlInterpolated and return list of entities

I am using C# in an ASP Core project with Entity Framework Core 5.0.3, and using the Pomelo EntityFrameworkCore for MySql.我在带有 Entity Framework Core 5.0.3 的 ASP Core 项目中使用 C#,并将 Pomelo EntityFrameworkCore 用于 MySql。

I am able to call standard SP's just fine with the below method:我可以使用以下方法调用标准 SP:

int recordCount = await context.Database.ExecuteSqlInterpolatedAsync($"call `SP_ON_MYSQL` ({param1}, {param2}");

The SP in question outputs a result set of the Entity that I want to capture, and when I try this:有问题的 SP 输出我想要捕获的实体的结果集,当我尝试这个时:

var qry = await context.ENITY.FromSqlInterpolated($"call `SP_ON_MYSQL` ({param1}, {param2})").SingleOrDefaultAsync();

I get the following error:我收到以下错误:

*'FromSqlRaw' or 'FromSqlInterpolated' was called with non-composable SQL and with a query composing over it. *'FromSqlRaw' 或 'FromSqlInterpolated' 是用不可组合的 SQL 调用的,并且有一个查询在它上面进行组合。

Thank you in advance for any help that can be offered.提前感谢您提供的任何帮助。 Consider calling 'AsEnumerable' after the method to perform the composition on the client side.*考虑在客户端执行组合的方法之后调用“AsEnumerable”。*

I have seen examples of this working with SQL Server, so please don't mark as already answered, unless you can show me an example that is not SQL Server specific.我已经看到了与 SQL 服务器一起使用的示例,因此请不要标记为已回答,除非您可以向我展示一个不是 SQL 服务器特定的示例。

Try this:尝试这个:

var qry = await context.ENITY
  .FromSqlInterpolated($"call `SP_ON_MYSQL` ({param1}, {param2})")
  .ToListAsync()
  .SingleOrDefault();

The answer of @Torvin is correct. @Torvin 的答案是正确的。

You need to add a AsEnumerable() , ToList() etc. call before the SingleOrDefault() call, if you are querying from a stored procedure.如果您从存储过程中查询,则需要在SingleOrDefault()调用之前添加AsEnumerable()ToList()等调用。 See Re-introduce detection for non-composable SQL in FromSql #17558 on the official EF Core repo for more information.有关更多信息,请参阅官方 EF Core存储库的 FromSql #17558 中对不可组合的 SQL 重新引入检测

Here is a fully working console program, that demonstrates the approach:这是一个完全工作的控制台程序,它演示了该方法:

using System.Diagnostics;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Pomelo.EntityFrameworkCore.MySql.Infrastructure;

namespace IssueConsoleTemplate
{
    public sealed class IceCream
    {
        public int IceCreamId { get; set; }
        public string Name { get; set; }
    }
    
    public class Context : DbContext
    {
        public DbSet<IceCream> IceCreams { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder
                .UseMySql(
                    "server=127.0.0.1;port=3306;user=root;password=;database=So67040870",
                    b => b.ServerVersion("8.0.21-mysql")
                          .CharSetBehavior(CharSetBehavior.NeverAppend))
                .UseLoggerFactory(
                    LoggerFactory.Create(
                        b => b
                            .AddConsole()
                            .AddFilter(level => level >= LogLevel.Information)))
                .EnableSensitiveDataLogging()
                .EnableDetailedErrors();
        }
    }

    internal class Program
    {
        private static void Main()
        {
            using var context = new Context();

            SetupDatabase(context);

            var iceCreamId = 1;
            var searchContacts = context.IceCreams
                .FromSqlInterpolated($"CALL `GetIceCreams`({iceCreamId})")
                .AsEnumerable() // <-- Mandatory: Use AsEnumerable(), ToList() etc. or you will get an exception.
                .SingleOrDefault();

            Trace.Assert(searchContacts != null);
            Trace.Assert(searchContacts.Name == "Vanilla");
        }

        private static void SetupDatabase(Context context)
        {
            context.Database.EnsureDeleted();
            context.Database.EnsureCreated();

            var connection = context.Database.GetDbConnection();
            connection.Open();

            using var command = connection.CreateCommand();
            command.CommandText = @"CREATE PROCEDURE `GetIceCreams`(`someArg` int)
BEGIN
    SELECT someArg as `IceCreamId`, 'Vanilla' as `Name`;
END";
            command.ExecuteNonQuery();
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM