Show / Hide Table of Contents

MSDN.WhiteKnight - Stack Overflow answers

Ответ на "Передать List в качестве параметра"

Answer 1176556

Link

Этого в явном виде нет в Entity Framework, и не может быть, так как не любая СУБД поддерживает "составные" параметры на уровне своего протокола. Но SQL Server, например, поддерживает: https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/sql/table-valued-parameters

Пусть у нас есть таблица Users, в которой поле Id целочисленного типа.

Мы можем вот так создать свой табличный тип:

CREATE TYPE ListOfIntegersType AS TABLE (i int) 

И выполнить запрос с его использованием так:

using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using System.Data;
using Microsoft.Data.SqlClient;
using Microsoft.Data.SqlClient.Server;
using Microsoft.EntityFrameworkCore;

namespace ConsoleApp1
{
    public class User
    {
        public int Id { get; set; }
        public string DisplayName { get; set; }        
    }

    public class MyContext : DbContext
    {
        public DbSet<User> Users { get; set; }        

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer(
                @"Data source=.\SQLEXPRESS;Initial catalog=Database;Integrated security=True;");
        }
    }

    class Program
    {
        static IEnumerable<SqlDataRecord> PrepareSequence(
            IEnumerable<int> src
            )
        {
            foreach (int item in src)
            {
                var ret = new SqlDataRecord(new SqlMetaData("x", SqlDbType.Int));
                ret.SetInt32(0, item);
                yield return ret;
            }
        }

        static void Main(string[] args)
        {
            MyContext entities = new MyContext();

            var users = entities.Users.FromSqlRaw(
                "SELECT * FROM Users WHERE Id IN (SELECT * FROM @tvpID)",
                new object[] {
                    new SqlParameter("@tvpID", SqlDbType.Structured)
                    {
                        TypeName = "dbo.ListOfIntegersType",
                        Value = PrepareSequence(new int[] { 6, 1365})
                    }
                });            
        }
    }
}

Выглядит не очень элегантно. Однако, EF для того и создан, что можно не писать вручную SQL, а использовать Linq Expressions с автоматической генерацией запросов. Тогда все это хозяйство можно переписать вот так:

var users = entities.Users.Where((x) => new int[] { 1, 2}.Contains(x.Id)); 

Необходимости в параметрах вообще нет, все и так строго типизировано. И все отлично работает! (На SQL Server по крайней мере.) Генерируемый провайдером запрос выглядит так:

SELECT 
[Extent1].[Id] AS [Id], 
[Extent1].[DisplayName] AS [DisplayName] 
FROM (SELECT 
[Users].[Id] AS [Id], 
[Users].[DisplayName] AS [DisplayName] 
FROM [dbo].[Users] AS [Users]) AS [Extent1]
WHERE [Extent1].[Id] IN (1,2)

Content is retrieved from StackExchange API.

Auto-generated by ruso-archive tools.

Back to top Stack Overflow answers (published from sources in GitHub repository). Copyright (c) 2020, MSDN.WhiteKnight. Content licensed under BSD 3-Clause License.
Generated by DocFX