Преобразование выражения LINQ в хранимую процедуру SQL Server - PullRequest
0 голосов
/ 24 апреля 2019

В серверной части моего мобильного приложения Azure .NET мне нужно найти все строки, в которых столбец, состоящий из строки с разделителями-запятыми, содержит все строки в списке.Я использую следующее выражение LINQ, которое было протестировано:

List<Items> filteredItems = _context.Items
                                    .Where(item => colorsToFilter.All(color => item.Colors.Contains(color)))
                                    .ToList();

Однако EF6 не поддерживает .All в выражении LINQ.Поэтому я пытаюсь преобразовать это выражение в хранимую процедуру SQL, которая принимает список строк в качестве параметра.

Примеры столбцов из обеих таблиц, использованных в запросе:

Colors:                            ColorsToFilter:

1     blue,green,red               1     blue
2     green                        2     green
3     blue,green,red,black         3     red
4     orange,blue,green,red,gray

Все элементы в ColorsToFilter (List<string>) должны быть в Colors.Таким образом, строки 1, 3 и 4 будут возвращены в этом примере.

Как бы я сделал это в SQL, используя хранимую процедуру с параметром таблицы, представляющим список?

Ответы [ 2 ]

1 голос
/ 25 апреля 2019

Лично я расположил бы структуру моей таблицы так, чтобы данные, которые я хотел запросить таким образом, не были в списке csv в столбце таблицы.

Если вы решили использовать хранимую процедуру SQL, вы можете использоватьнижеприведенное.Вы можете создать тип таблицы и передать его в приложение. Затем вы можете использовать функцию string_split, чтобы превратить ваш список csv в таблицу, которую вы можете запросить, и оператор all, чтобы проверить, есть ли все в параметре таблицы.Последний бит, где я вызываю процедуру, которую вы бы не делали, вы вместо этого вызывали бы хранимую процедуру в вашем c #, в c # вы можете создать таблицу данных с одним строковым столбцом под названием StringValue, заполнить его списком цветов фильтра и представить какПараметр sql (обратите внимание, что вам нужно указать имя вашего пользовательского типа, иначе вы получите ошибку.)

   CREATE DATABASE Mycolours;
go
USE Mycolours
GO

/****** Object:  Table [dbo].[Colours]    Script Date: 24/04/2019 23:13:45 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[Colours](
    [ColourID] [int] NOT NULL,
    [ColourList] [nvarchar](50) NOT NULL
) ON [PRIMARY]
GO
GO
insert into [Colours](ColourID,ColourList) values(1,'blue,green,red'),(2,'green'),(3,'blue,green,red,black'),(4,'orange,blue,green,red,gray')
/****** Object:  StoredProcedure [dbo].[SPGetAllMyColours]    Script Date: 24/04/2019 23:14:10 ******/
SET ANSI_NULLS ON
GO
GO

/****** Object:  UserDefinedTableType [dbo].[StringValues]    Script Date: 24/04/2019 23:14:32 ******/
CREATE TYPE [dbo].[StringValues] AS TABLE(
    [StringValue] [nvarchar](50) NOT NULL,
    PRIMARY KEY CLUSTERED 
(
    [StringValue] ASC
)WITH (IGNORE_DUP_KEY = OFF)
)
GO


SET QUOTED_IDENTIFIER ON
GO

-- =============================================
-- Author:      <Author,,Name>
-- Create date: <Create Date,,>
-- Description: <Description,,>
-- =============================================
CREATE PROCEDURE [dbo].[SPGetAllMyColours]
    @colours dbo.StringValues READONLY
AS
BEGIN
    select * from colours where not exists(select StringValue from @colours where StringValue = all(select value from string_split(colours.ColourList,',')));
END
GO



GO

DECLARE @return_value int
declare @filterColours dbo.StringValues;

insert into @filterColours(StringValue) values('blue'),('green'),('red');

EXEC    @return_value = [dbo].[SPGetAllMyColours] @filterColours

SELECT  'Return Value' = @return_value

GO
0 голосов
/ 25 апреля 2019

Поскольку вы используете All, это на самом деле просто - вы можете просто объединить Where условия по вашему запросу и остаться в EF:

var q = _context.Items.AsQueryable();
foreach (var cf in colorsToFilter) {
    q = q.Where(item => item.Colors.Contains(cf));
}

var filteredItems = q.ToList();

Снова используя LINQ, вы можете сделать это в одном выражении:

var filteredItems = colorsToFilter.Aggregate(_context.Items.AsQueryable(), (q, f) => q.Where(item => item.Colors.Contains(f))).ToList();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...