НСкоторыС аспСкты ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠΈ LINQ-запросов Π² C#.NET для MS SQL Server

LINQ вошСл Π² .NET ΠΊΠ°ΠΊ Π½ΠΎΠ²Ρ‹ΠΉ ΠΌΠΎΡ‰Π½Ρ‹ΠΉ язык манипуляции с Π΄Π°Π½Π½Ρ‹ΠΌΠΈ. LINQ to SQL ΠΊΠ°ΠΊ Ρ‡Π°ΡΡ‚ΡŒ Π΅Π³ΠΎ позволяСт достаточно ΡƒΠ΄ΠΎΠ±Π½ΠΎ ΠΎΠ±Ρ‰Π°Ρ‚ΡŒΡΡ с Π‘Π£Π‘Π” с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Entity Framework. Однако, достаточно часто примСняя Π΅Π³ΠΎ, Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΈ Π·Π°Π±Ρ‹Π²Π°ΡŽΡ‚ ΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Π½Π° Ρ‚ΠΎ, ΠΊΠ°ΠΊΠΎΠΉ ΠΈΠΌΠ΅Π½Π½ΠΎ SQL-запрос Π±ΡƒΠ΄Π΅Ρ‚ Π³Π΅Π½Π΅Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ queryable provider, Π² вашСм случаС β€” Entity Framework.

Π Π°Π·Π±Π΅Ρ€Π΅ΠΌ Π΄Π²Π° основных ΠΌΠΎΠΌΠ΅Π½Ρ‚Π° Π½Π° ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅.
Для этого Π² SQL Server создадим Π±Π°Π·Ρƒ Π΄Π°Π½Π½Ρ‹Ρ… Test, Π° Π² Π½Π΅ΠΉ создадим Π΄Π²Π΅ Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅Π³ΠΎ запроса:

Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ Ρ‚Π°Π±Π»ΠΈΡ†

USE [TEST]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[Ref](
	[ID] [int] NOT NULL,
	[ID2] [int] NOT NULL,
	[Name] [nvarchar](255) NOT NULL,
	[InsertUTCDate] [datetime] NOT NULL,
 CONSTRAINT [PK_Ref] PRIMARY KEY CLUSTERED 
(
	[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[Ref] ADD  CONSTRAINT [DF_Ref_InsertUTCDate]  DEFAULT (getutcdate()) FOR [InsertUTCDate]
GO

USE [TEST]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[Customer](
	[ID] [int] NOT NULL,
	[Name] [nvarchar](255) NOT NULL,
	[Ref_ID] [int] NOT NULL,
	[InsertUTCDate] [datetime] NOT NULL,
	[Ref_ID2] [int] NOT NULL,
 CONSTRAINT [PK_Customer] PRIMARY KEY CLUSTERED 
(
	[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[Customer] ADD  CONSTRAINT [DF_Customer_Ref_ID]  DEFAULT ((0)) FOR [Ref_ID]
GO

ALTER TABLE [dbo].[Customer] ADD  CONSTRAINT [DF_Customer_InsertUTCDate]  DEFAULT (getutcdate()) FOR [InsertUTCDate]
GO

Π’Π΅ΠΏΠ΅Ρ€ΡŒ Π·Π°ΠΏΠΎΠ»Π½ΠΈΠΌ Ρ‚Π°Π±Π»ΠΈΡ†Ρƒ Ref с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ запуска ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅Π³ΠΎ скрипта:

Π—Π°ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ Ref

USE [TEST]
GO

DECLARE @ind INT=1;

WHILE(@ind<1200000)
BEGIN
	INSERT INTO [dbo].[Ref]
           ([ID]
           ,[ID2]
           ,[Name])
    SELECT
           @ind
           ,@ind
           ,CAST(@ind AS NVARCHAR(255));

	SET @ind=@ind+1;
END 
GO

Аналогично Π·Π°ΠΏΠΎΠ»Π½ΠΈΠΌ Ρ‚Π°Π±Π»ΠΈΡ†Ρƒ Customer с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅Π³ΠΎ скрипта:

Π—Π°ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ Customer

USE [TEST]
GO

DECLARE @ind INT=1;
DECLARE @ind_ref INT=1;

WHILE(@ind<=12000000)
BEGIN
	IF(@ind%3=0) SET @ind_ref=1;
	ELSE IF (@ind%5=0) SET @ind_ref=2;
	ELSE IF (@ind%7=0) SET @ind_ref=3;
	ELSE IF (@ind%11=0) SET @ind_ref=4;
	ELSE IF (@ind%13=0) SET @ind_ref=5;
	ELSE IF (@ind%17=0) SET @ind_ref=6;
	ELSE IF (@ind%19=0) SET @ind_ref=7;
	ELSE IF (@ind%23=0) SET @ind_ref=8;
	ELSE IF (@ind%29=0) SET @ind_ref=9;
	ELSE IF (@ind%31=0) SET @ind_ref=10;
	ELSE IF (@ind%37=0) SET @ind_ref=11;
	ELSE SET @ind_ref=@ind%1190000;
	
	INSERT INTO [dbo].[Customer]
	           ([ID]
	           ,[Name]
	           ,[Ref_ID]
	           ,[Ref_ID2])
	     SELECT
	           @ind,
	           CAST(@ind AS NVARCHAR(255)),
	           @ind_ref,
	           @ind_ref;


	SET @ind=@ind+1;
END
GO

Π’Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ ΠΌΡ‹ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ»ΠΈ Π΄Π²Π΅ Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹, Π² ΠΎΠ΄Π½ΠΎΠΉ ΠΈΠ· ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… Π±ΠΎΠ»Π΅Π΅ 1 ΠΌΠ»Π½ строк Π΄Π°Π½Π½Ρ‹Ρ…, Π° Π² Π΄Ρ€ΡƒΠ³ΠΎΠΉ-Π±ΠΎΠ»Π΅Π΅ 10 ΠΌΠ»Π½ строк Π΄Π°Π½Π½Ρ‹Ρ….

Π’Π΅ΠΏΠ΅Ρ€ΡŒ Π² Visual Studio Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ тСстовый ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ Visual C# Console App (.NET Framework):

НСкоторыС аспСкты ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠΈ LINQ-запросов Π² C#.NET для MS SQL Server

Π”Π°Π»Π΅Π΅, Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ для взаимодСйствия с Π±Π°Π·ΠΎΠΉ Π΄Π°Π½Π½Ρ‹Ρ… Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΡƒ для Entity Framework.
Π§Ρ‚ΠΎΠ±Ρ‹ Π΅Π΅ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ, Π½Π°ΠΆΠΌΠ΅ΠΌ Π½Π° ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ ΠΏΡ€Π°Π²ΠΎΠΉ ΠΊΠ½ΠΎΠΏΠΊΠΎΠΉ ΠΌΡ‹ΡˆΠΈ ΠΈ Π²Ρ‹Π±Π΅Ρ€Π΅ΠΌ Π² контСкстном мСню Manage NuGet Packages:

НСкоторыС аспСкты ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠΈ LINQ-запросов Π² C#.NET для MS SQL Server

Π—Π°Ρ‚Π΅ΠΌ Π² появившСмся ΠΎΠΊΠ½Π΅ управлСния NuGet-ΠΏΠ°ΠΊΠ΅Ρ‚Π°ΠΌΠΈ Π² ΠΎΠΊΠ½Π΅ поиска Π²Π²Π΅Π΄Π΅ΠΌ слово Β«Entity FrameworkΒ» ΠΈ Π²Ρ‹Π±Π΅Ρ€Π΅ΠΌ ΠΏΠ°ΠΊΠ΅Ρ‚ Entity Framework ΠΈ установим Π΅Π³ΠΎ:

НСкоторыС аспСкты ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠΈ LINQ-запросов Π² C#.NET для MS SQL Server

Π”Π°Π»Π΅Π΅ Π² Ρ„Π°ΠΉΠ»Π΅ App.config послС закрытия элСмСнта configSections Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ Π±Π»ΠΎΠΊ:

<connectionStrings>
    <add name="DBConnection" connectionString="data source=ИМЯ_Π­ΠšΠ—Π•ΠœΠŸΠ›Π―Π Π_MSSQL;Initial Catalog=TEST;Integrated Security=True;" providerName="System.Data.SqlClient" />
</connectionStrings>

Π’ connectionString Π½ΡƒΠΆΠ½ΠΎ Π²ΠΏΠΈΡΠ°Ρ‚ΡŒ строку ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ.

Π’Π΅ΠΏΠ΅Ρ€ΡŒ создадим Π² ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹Ρ… Ρ„Π°ΠΉΠ»Π°Ρ… 3 интСрфСйса:

  1. РСализация интСрфСйса IBaseEntityID
    namespace TestLINQ
    {
        public interface IBaseEntityID
        {
            int ID { get; set; }
        }
    }
    

  2. РСализация интСрфСйса IBaseEntityName
    namespace TestLINQ
    {
        public interface IBaseEntityName
        {
            string Name { get; set; }
        }
    }
    

  3. РСализация интСрфСйса IBaseNameInsertUTCDate
    namespace TestLINQ
    {
        public interface IBaseNameInsertUTCDate
        {
            DateTime InsertUTCDate { get; set; }
        }
    }
    

И Π² ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΠΎΠΌ Ρ„Π°ΠΉΠ»Π΅ создадим Π±Π°Π·ΠΎΠ²Ρ‹ΠΉ класс BaseEntity для Π½Π°ΡˆΠΈΡ… Π΄Π²ΡƒΡ… сущностСй, Π² ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π²ΠΎΠΉΠ΄ΡƒΡ‚ ΠΎΠ±Ρ‰ΠΈΠ΅ поля:

РСализация Π±Π°Π·ΠΎΠ²ΠΎΠ³ΠΎ класса BaseEntity

namespace TestLINQ
{
    public class BaseEntity : IBaseEntityID, IBaseEntityName, IBaseNameInsertUTCDate
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public DateTime InsertUTCDate { get; set; }
    }
}

Π”Π°Π»Π΅Π΅ Π² ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹Ρ… Ρ„Π°ΠΉΠ»Π°Ρ… создадим наши Π΄Π²Π΅ сущности:

  1. РСализация класса Ref
    using System.ComponentModel.DataAnnotations.Schema;
    
    namespace TestLINQ
    {
        [Table("Ref")]
        public class Ref : BaseEntity
        {
            public int ID2 { get; set; }
        }
    }
    

  2. РСализация класса Customer
    using System.ComponentModel.DataAnnotations.Schema;
    
    namespace TestLINQ
    {
        [Table("Customer")]
        public class Customer: BaseEntity
        {
            public int Ref_ID { get; set; }
            public int Ref_ID2 { get; set; }
        }
    }
    

Π’Π΅ΠΏΠ΅Ρ€ΡŒ создадим Π² ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΠΎΠΌ Ρ„Π°ΠΉΠ»Π΅ контСкст UserContext:

РСализация класса UserContex

using System.Data.Entity;

namespace TestLINQ
{
    public class UserContext : DbContext
    {
        public UserContext()
            : base("DbConnection")
        {
            Database.SetInitializer<UserContext>(null);
        }

        public DbSet<Customer> Customer { get; set; }
        public DbSet<Ref> Ref { get; set; }
    }
}

ΠŸΠΎΠ»ΡƒΡ‡ΠΈΠ»ΠΈ Π³ΠΎΡ‚ΠΎΠ²ΠΎΠ΅ Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅ для провСдСния тСстов ΠΏΠΎ ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠΈ с LINQ to SQL Ρ‡Π΅Ρ€Π΅Π· EF для MS SQL Server:

НСкоторыС аспСкты ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠΈ LINQ-запросов Π² C#.NET для MS SQL Server

Π’Π΅ΠΏΠ΅Ρ€ΡŒ Π² Ρ„Π°ΠΉΠ» Program.cs Π²Π²Π΅Π΄Π΅ΠΌ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ ΠΊΠΎΠ΄:

Π€Π°ΠΉΠ» Program.cs

using System;
using System.Collections.Generic;
using System.Linq;

namespace TestLINQ
{
    class Program
    {
        static void Main(string[] args)
        {
            using (UserContext db = new UserContext())
            {
                var dblog = new List<string>();
                db.Database.Log = dblog.Add;

                var query = from e1 in db.Customer
                            from e2 in db.Ref
                            where (e1.Ref_ID == e2.ID)
                                 && (e1.Ref_ID2 == e2.ID2)
                            select new { Data1 = e1.Name, Data2 = e2.Name };

                var result = query.Take(1000).ToList();

                Console.WriteLine(dblog[1]);

                Console.ReadKey();
            }
        }
    }
}

Π”Π°Π»Π΅Π΅ запустим наш ΠΏΡ€ΠΎΠ΅ΠΊΡ‚.

Π’ ΠΊΠΎΠ½Ρ†Π΅ Ρ€Π°Π±ΠΎΡ‚Ρ‹ Π½Π° консоль Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹Π²Π΅Π΄Π΅Π½ΠΎ:

Π‘Π³Π΅Π½Π΅Ρ€ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹ΠΉ SQL-запрос

SELECT TOP (1000) 
    [Extent1].[Ref_ID] AS [Ref_ID], 
    [Extent1].[Name] AS [Name], 
    [Extent2].[Name] AS [Name1]
    FROM  [dbo].[Customer] AS [Extent1]
    INNER JOIN [dbo].[Ref] AS [Extent2] ON ([Extent1].[Ref_ID] = [Extent2].[ID]) AND ([Extent1].[Ref_ID2] = [Extent2].[ID2])

Π’. Π΅. Π² Ρ†Π΅Π»ΠΎΠΌ вСсьма Π½Π΅ΠΏΠ»ΠΎΡ…ΠΎ LINQ-запрос сгСнСрировал SQL-запрос ΠΊ Π‘Π£Π‘Π” MS SQL Server.

Π’Π΅ΠΏΠ΅Ρ€ΡŒ ΠΈΠ·ΠΌΠ΅Π½ΠΈΠΌ условиС И Π½Π° Π˜Π›Π˜ Π² LINQ-запросС:

LINQ-запрос

var query = from e1 in db.Customer
                            from e2 in db.Ref
                            where (e1.Ref_ID == e2.ID)
                                || (e1.Ref_ID2 == e2.ID2)
                            select new { Data1 = e1.Name, Data2 = e2.Name };

И вновь запустим нашС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅.

Π’Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ Π²Ρ‹Π»Π΅Ρ‚ΠΈΡ‚ с ошибкой, связанной с ΠΏΡ€Π΅Π²Ρ‹ΡˆΠ΅Π½ΠΈΠ΅ΠΌ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ выполнСния ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹ Π² 30 сСк:

НСкоторыС аспСкты ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠΈ LINQ-запросов Π² C#.NET для MS SQL Server

Если ΠΏΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ ΠΊΠ°ΠΊΠΎΠΉ запрос ΠΏΡ€ΠΈ этом Π±Ρ‹Π» сгСнСрирован LINQ:

НСкоторыС аспСкты ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠΈ LINQ-запросов Π² C#.NET для MS SQL Server
, Ρ‚ΠΎ ΠΌΠΎΠΆΠ½ΠΎ ΡƒΠ±Π΅Π΄ΠΈΡ‚ΡŒΡΡ Π² Ρ‚ΠΎΠΌ, Ρ‡Ρ‚ΠΎ Π²Ρ‹Π±ΠΎΡ€ΠΊΠ° происходит Ρ‡Π΅Ρ€Π΅Π· Π΄Π΅ΠΊΠ°Ρ€Ρ‚ΠΎΠ²ΠΎ ΠΏΡ€ΠΎΠΈΠ·Π²Π΅Π΄Π΅Π½ΠΈΠ΅ Π΄Π²ΡƒΡ… мноТСств (Ρ‚Π°Π±Π»ΠΈΡ†):

Π‘Π³Π΅Π½Π΅Ρ€ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹ΠΉ SQL-запрос

SELECT TOP (1000) 
    [Extent1].[Ref_ID] AS [Ref_ID], 
    [Extent1].[Name] AS [Name], 
    [Extent2].[Name] AS [Name1]
    FROM  [dbo].[Customer] AS [Extent1]
    CROSS JOIN [dbo].[Ref] AS [Extent2]
    WHERE [Extent1].[Ref_ID] = [Extent2].[ID] OR [Extent1].[Ref_ID2] = [Extent2].[ID2]

Π”Π°Π²Π°ΠΉΡ‚Π΅ ΠΏΠ΅Ρ€Π΅ΠΏΠΈΡˆΠ΅ΠΌ LINQ-запрос ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ:

ΠžΠΏΡ‚ΠΈΠΌΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹ΠΉ LINQ-запрос

var query = (from e1 in db.Customer
                   join e2 in db.Ref
                   on e1.Ref_ID equals e2.ID
                   select new { Data1 = e1.Name, Data2 = e2.Name }).Union(
                        from e1 in db.Customer
                        join e2 in db.Ref
                        on e1.Ref_ID2 equals e2.ID2
                        select new { Data1 = e1.Name, Data2 = e2.Name });

Π’ΠΎΠ³Π΄Π° ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠΌ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ SQL-запрос:

SQL-запрос

SELECT 
    [Limit1].[C1] AS [C1], 
    [Limit1].[C2] AS [C2], 
    [Limit1].[C3] AS [C3]
    FROM ( SELECT DISTINCT TOP (1000) 
        [UnionAll1].[C1] AS [C1], 
        [UnionAll1].[Name] AS [C2], 
        [UnionAll1].[Name1] AS [C3]
        FROM  (SELECT 
            1 AS [C1], 
            [Extent1].[Name] AS [Name], 
            [Extent2].[Name] AS [Name1]
            FROM  [dbo].[Customer] AS [Extent1]
            INNER JOIN [dbo].[Ref] AS [Extent2] ON [Extent1].[Ref_ID] = [Extent2].[ID]
        UNION ALL
            SELECT 
            1 AS [C1], 
            [Extent3].[Name] AS [Name], 
            [Extent4].[Name] AS [Name1]
            FROM  [dbo].[Customer] AS [Extent3]
            INNER JOIN [dbo].[Ref] AS [Extent4] ON [Extent3].[Ref_ID2] = [Extent4].[ID2]) AS [UnionAll1]
    )  AS [Limit1]

Π£Π²Ρ‹, Π½ΠΎ Π² LINQ-запросах условиС соСдинСния ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΎΠ΄Π½ΠΎ, ΠΏΠΎΡ‚ΠΎΠΌΡƒ здСсь Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ эквивалСнтный запрос Ρ‡Π΅Ρ€Π΅Π· Π΄Π²Π° запроса ΠΏΠΎ ΠΊΠ°ΠΆΠ΄ΠΎΠΌΡƒ ΡƒΡΠ»ΠΎΠ²ΠΈΡŽ с ΠΏΠΎΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΌ объСдинСниСм ΠΈΡ… Ρ‡Π΅Ρ€Π΅Π· Union для удалСния Π΄ΡƒΠ±Π»ΠΈΠΊΠ°Ρ‚ΠΎΠ² срСди строк.
Π”Π°, запросы Π² ΠΎΠ±Ρ‰Π΅ΠΌ случаС получатся нСэквивалСнтными с Ρ‚Π΅ΠΌ ΡƒΡ‡Π΅Ρ‚ΠΎΠΌ, Ρ‡Ρ‚ΠΎ ΠΌΠΎΠ³ΡƒΡ‚ Π±Ρ‹Ρ‚ΡŒ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π΅Π½Ρ‹ ΠΏΠΎΠ»Π½Ρ‹Π΅ Π΄ΡƒΠ±Π»ΠΈΠΊΠ°Ρ‚Ρ‹ строк. Однако, Π² Ρ€Π΅Π°Π»ΡŒΠ½ΠΎΠΉ ΠΆΠΈΠ·Π½ΠΈ ΠΏΠΎΠ»Π½Ρ‹Π΅ Π΄ΡƒΠ±Π»ΠΈΡ€ΡƒΡŽΡ‰ΠΈΠ΅ строки Π½Π΅ Π½ΡƒΠΆΠ½Ρ‹ ΠΈ ΠΎΡ‚ Π½ΠΈΡ… ΡΡ‚Π°Ρ€Π°ΡŽΡ‚ΡΡ ΠΈΠ·Π±Π°Π²Π»ΡΡ‚ΡŒΡΡ.

Π’Π΅ΠΏΠ΅Ρ€ΡŒ сравним ΠΏΠ»Π°Π½Ρ‹ выполнСния Π΄Π²ΡƒΡ… этих запросов:

  1. для CROSS JOIN Π² срСднСм врСмя выполнСния 195 сСк:
    НСкоторыС аспСкты ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠΈ LINQ-запросов Π² C#.NET для MS SQL Server
  2. для INNER JOIN-UNION Π² срСднСм врСмя выполнСния ΠΌΠ΅Π½Π΅Π΅ 24 сСк:
    НСкоторыС аспСкты ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠΈ LINQ-запросов Π² C#.NET для MS SQL Server

Как Π²ΠΈΠ΄Π½ΠΎ ΠΈΠ· Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠ², для Π΄Π²ΡƒΡ… Ρ‚Π°Π±Π»ΠΈΡ† с ΠΌΠΈΠ»Π»ΠΈΠΎΠ½Π°ΠΌΠΈ записСй ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹ΠΉ LINQ-запрос Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ Π² Ρ€Π°Π·Ρ‹ быстрСС, Ρ‡Π΅ΠΌ Π½Π΅ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹ΠΉ.

Для Π²Π°Ρ€ΠΈΠ°Π½Ρ‚Π° с И Π² условиях LINQ-запрос Π²ΠΈΠ΄Π°:

LINQ-запрос

var query = from e1 in db.Customer
                            from e2 in db.Ref
                            where (e1.Ref_ID == e2.ID)
                                 && (e1.Ref_ID2 == e2.ID2)
                            select new { Data1 = e1.Name, Data2 = e2.Name };

ΠΏΠΎΡ‡Ρ‚ΠΈ всСгда Π±ΡƒΠ΄Π΅Ρ‚ сгСнСрирован ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½Ρ‹ΠΉ SQL-запрос, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹ΠΏΠΎΠ»Π½ΡΡ‚ΡŒΡΡ Π² срСднСм ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π½ΠΎ 1 сСк:

НСкоторыС аспСкты ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠΈ LINQ-запросов Π² C#.NET для MS SQL Server
Π’Π°ΠΊΠΆΠ΅ для манипуляций LINQ to Objects вмСсто запроса Π²ΠΈΠ΄Π°:

LINQ-запрос (1-ΠΉ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚)

var query = from e1 in seq1
                            from e2 in seq2
                            where (e1.Key1==e2.Key1)
                               && (e1.Key2==e2.Key2)
                            select new { Data1 = e1.Data, Data2 = e2.Data };

ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ запрос Π²ΠΈΠ΄Π°:

LINQ-запрос (2-ΠΉ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚)

var query = from e1 in seq1
                            join e2 in seq2
                            on new { e1.Key1, e1.Key2 } equals new { e2.Key1, e2.Key2 }
                            select new { Data1 = e1.Data, Data2 = e2.Data };

Π³Π΄Π΅:

ΠžΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ΠΈΠ΅ Π΄Π²ΡƒΡ… массивов

Para[] seq1 = new[] { new Para { Key1 = 1, Key2 = 2, Data = "777" }, new Para { Key1 = 2, Key2 = 3, Data = "888" }, new Para { Key1 = 3, Key2 = 4, Data = "999" } };
Para[] seq2 = new[] { new Para { Key1 = 1, Key2 = 2, Data = "777" }, new Para { Key1 = 2, Key2 = 3, Data = "888" }, new Para { Key1 = 3, Key2 = 5, Data = "999" } };

, Π° Ρ‚ΠΈΠΏ Para опрСдСляСтся ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ:

ΠžΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ΠΈΠ΅ Ρ‚ΠΈΠΏΠ° Para

class Para
{
        public int Key1, Key2;
        public string Data;
}

Π’Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ ΠΌΡ‹ рассмотрСли Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ аспСкты Π² ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠΈ LINQ-запросов ΠΊ MS SQL Server.

К соТалСнию Π΄Π°ΠΆΠ΅ ΠΎΠΏΡ‹Ρ‚Π½Ρ‹Π΅ ΠΈ Π²Π΅Π΄ΡƒΡ‰ΠΈΠ΅ .NET-Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΈ Π·Π°Π±Ρ‹Π²Π°ΡŽΡ‚ ΠΎ Ρ‚ΠΎΠΌ, Ρ‡Ρ‚ΠΎ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΠΏΠΎΠ½ΠΈΠΌΠ°Ρ‚ΡŒ Ρ‡Ρ‚ΠΎ Π΄Π΅Π»Π°ΡŽΡ‚ Π·Π° ΠΊΠ°Π΄Ρ€ΠΎΠΌ Ρ‚Π΅ инструкции, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΎΠ½ΠΈ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚. Π˜Π½Π°Ρ‡Π΅ ΠΎΠ½ΠΈ становятся ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ‚ΠΎΡ€Π°ΠΌΠΈ ΠΈ ΠΌΠΎΠ³ΡƒΡ‚ Π·Π°Π»ΠΎΠΆΠΈΡ‚ΡŒ Π±ΠΎΠΌΠ±Ρƒ Π·Π°ΠΌΠ΅Π΄Π»Π΅Π½Π½ΠΎΠ³ΠΎ дСйствия Π² Π±ΡƒΠ΄ΡƒΡ‰Π΅ΠΌ ΠΊΠ°ΠΊ ΠΏΡ€ΠΈ ΠΌΠ°ΡΡˆΡ‚Π°Π±ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠΈ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ½ΠΎΠ³ΠΎ Ρ€Π΅ΡˆΠ΅Π½ΠΈΡ, Ρ‚Π°ΠΊ ΠΈ ΠΏΡ€ΠΈ Π½Π΅Π·Π½Π°Ρ‡ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Ρ… измСнСниях Π²Π½Π΅ΡˆΠ½ΠΈΡ… условий срСды.

Π’Π°ΠΊΠΆΠ΅ нСбольшой ΠΎΠ±Π·ΠΎΡ€ проводился ΠΈ здСсь.

Π˜ΡΡ…ΠΎΠ΄Π½ΠΈΠΊΠΈ для тСста-сам ΠΏΡ€ΠΎΠ΅ΠΊΡ‚, созданиС Ρ‚Π°Π±Π»ΠΈΡ† Π² Π±Π°Π·Π΅ Π΄Π°Π½Π½Ρ‹Ρ… TEST, Π° Ρ‚Π°ΠΊΠΆΠ΅ Π½Π°ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ Π΄Π°Π½Π½Ρ‹ΠΌΠΈ этих Ρ‚Π°Π±Π»ΠΈΡ† находится здСсь.
Π’Π°ΠΊΠΆΠ΅ Π² этом Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΈ Π² ΠΏΠ°ΠΏΠΊΠ΅ Plans находятся ΠΏΠ»Π°Π½Ρ‹ выполнСния запросов с условиями Π˜Π›Π˜.

Π˜ΡΡ‚ΠΎΡ‡Π½ΠΈΠΊ: habr.com