65.9K
CodeProject 正在变化。 阅读更多。
Home

使用共生微型 ORM 进行并行查询

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.67/5 (5投票s)

2019年1月20日

CPOL

3分钟阅读

viewsIcon

8997

downloadIcon

114

使用共生微型 ORM 执行并行查询

引言

本文将解释如何并行运行查询并使用共生 ORM 返回结果。 我们还将解释如何解决查询出现错误的情况,以及如何隔离问题查询。

共生是一个免费的 .NET ORM,支持以下数据库供应商:SQL Server、SQL Azure、MySQL、Sqlite、Oracle、PostgreSql、Firebird、DB2/LUW。

本文将重点介绍 SQL Server 数据库。

本文假设您对 C# 和 SQL Server 有很强的了解。

背景

您将需要一个 SQL Server 数据库,它可以是本地数据库文件、服务器数据库或 Azure SQL 数据库。

请确保将您的项目构建为 x64。 请参见菜单:“生成 \ 配置管理器”。

步骤 1:创建 TestItem1、TestItem2 表

运行以下 SQL 脚本来创建我们将用于本文的表。

CREATE TABLE [dbo].[TestItem1](
	[TestId] [int] IDENTITY(1,1) NOT NULL,
	[StringData] [nvarchar](50) NOT NULL,
	[DateData] [datetime] NOT NULL
) ON [PRIMARY];


CREATE TABLE [dbo].[TestItem2](
	[TestId] [int] IDENTITY(1,1) NOT NULL,
	[StringData] [nvarchar](50) NOT NULL,
	[DateData] [datetime] NOT NULL
) ON [PRIMARY];

步骤 2:创建一个项目并添加共生 ORM NuGet 包

在 Visual Studio 中为 .NET 4.6.1 或更高版本创建一个新的 C# 控制台项目。

然后添加 Nuget 包“Symbiotic_Micro_ORM_Net_Standard_x64”。 您可以使用主菜单:“项目 \ 管理 Nuget 包...

您可能需要在“解决方案资源管理器”中刷新项目以更新引用。

步骤 3:创建 TestItem1 和 TestItem2 类

这些类将用于表示您在步骤 1 中创建的表。

[DatabaseTable("TestItem1"), DebuggerDisplay("TestItem1: {TestId} {DateData} {StringData}")]

public class TestItem1
{
    [DatabaseColumnAttribute("TestId", IsPrimaryKey = true, IsIdentityColumn = true)]
    public int TestId { get; set; }

    [DatabaseColumnAttribute("StringData")]
    public string StringData { get; set; }

    [DatabaseColumnAttribute("DateData")]
    public DateTime DateData { get; set; }
}

[DatabaseTable("TestItem2"), DebuggerDisplay("TestItem2: {TestId} {DateData} {StringData}")]
public class TestItem2
{
    [DatabaseColumnAttribute("TestId", IsPrimaryKey = true, IsIdentityColumn = true)]
    public int TestId { get; set; }

    [DatabaseColumnAttribute("StringData")]
    public string StringData { get; set; }

    [DatabaseColumnAttribute("DateData")]
    public DateTime DateData { get; set; }
}

步骤 4:为共生 ORM 添加 Usings

将以下 using 行添加到“Program”类的顶部。

using FrozenElephant.Symbiotic;
using FrozenElephant.Symbiotic.DataProviderSqlServer; // Using the Sql Server data provider

步骤 5:初始化工厂类

在“Main”方法的开头添加以下代码行。

这些行初始化 factory 类并设置数据库连接字符串。

您需要修改连接字符串以匹配您的数据库、服务器和用户/密码。

 // Initialize the factory and set the connection string
_DBTypesFactory = new DatabaseTypesFactorySqlServer(); // using sql server provider
_DBTypesFactory.ConnectionString = "Data Source=yourServer;
Initial Catalog=yourDatabase;User ID=ZZZZZZZ;Password=XXXXXX;Connect Timeout=35;
Encrypt=False;TrustServerCertificate=True;ApplicationIntent=ReadWrite;
MultiSubnetFailover=False;MultipleActiveResultSets=true;Enlist=false";

您的“Program”类现在应该如下面的代码所示

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
using FrozenElephant.Symbiotic;
using FrozenElephant.Symbiotic.DataProviderSqlServer; // Using the SQL Server data provider

namespace Advanced_Parallel_Queries_With_Symbiotic_CS
{
    // Make sure the build is set to x64
    class Program
    {
        // the factory is where all Symbiotic ORM objects are created, 
        // this allows the developer to override creation as needed.
        private static IDatabaseTypesFactory _DBTypesFactory;

        static void Main(string[] args)
        {
            // Initialize the factory and set the connection string
            _DBTypesFactory = new DatabaseTypesFactorySqlServer(); // using SQL Server provider
            _DBTypesFactory.ConnectionString = "Data Source=yourServer;
            Initial Catalog=yourDatabase;User ID=ZZZZZZZ;Password=XXXXXX;
            Connect Timeout=35;Encrypt=False;TrustServerCertificate=True;
            ApplicationIntent=ReadWrite;MultiSubnetFailover=False;
            MultipleActiveResultSets=true;Enlist=false";
        }
    }
}

步骤 6:添加创建测试记录的方法

将以下方法添加到“Program”类。

以下方法将用于创建稍后我们将查询的测试记录。

        public static void CreateRandomItems()
        {
            IList<testitem1> items = new List<testitem1>();

            for (int t = 0; t <= 1000; t++)
            {
                var emp = new TestItem1();
                emp.DateData = DateTime.Now;
                emp.StringData = Guid.NewGuid().ToString();

                items.Add(emp);
            }

            IObjectWriter writer = _DBTypesFactory.CreateObjectWriter();
            writer.InsertUpdate(items);
        }

        public static void CreateRandomItems2()
        {
            IList<testitem2> items = new List<testitem2>();

            for (int t = 0; t <= 1000; t++)
            {
                var emp = new TestItem2();
                emp.DateData = DateTime.Now;
                emp.StringData = Guid.NewGuid().ToString();

                items.Add(emp);
            }

            IObjectWriter writer = _DBTypesFactory.CreateObjectWriter();
            writer.InsertUpdate(items);
        }

步骤 7:将以下行添加到“Main”方法

将以下方法调用添加到“Main”方法的末尾。

这些调用将创建用于稍后查询的记录。

// Create test records
CreateRandomItems();

CreateRandomItems2();   

步骤 8:创建并行加载方法

此方法演示了并行运行多个查询并返回包含 TestItem1TestItem2 项集合的集合。

我们构建一个 ISqlQuery 项的集合并调用“loader.ParallelLoadItems”来并行运行查询。

        public static void ParallelLoadItems()
        {
            //build a collection of queries to run
            IList<isqlquery> queries = new List<isqlquery>();

            ISqlQuery s1 = _DBTypesFactory.CreateSqlQuery
            ("Select * from TestItem1", "ParallelLoads.ParallelLoadItems1", typeof(TestItem1));
            s1.AddRowLimit(_DBTypesFactory.DatabaseType, 2000);
            queries.Add(s1);

            ISqlQuery e1 = _DBTypesFactory.CreateSqlQuery("Select * 
            from TestItem1", "ParallelLoads.ParallelLoadItems2", typeof(TestItem1));
            e1.AddRowLimit(_DBTypesFactory.DatabaseType, 2000);
            queries.Add(e1);

            ISqlQuery a1 = _DBTypesFactory.CreateSqlQuery("Select * 
            from TestItem2", "ParallelLoads.ParallelLoadItems3", typeof(TestItem2));
            a1.AddRowLimit(_DBTypesFactory.DatabaseType, 2000);
            queries.Add(a1);

            ISqlQuery p1 = _DBTypesFactory.CreateSqlQuery("Select * 
            from TestItem1", "ParallelLoads.ParallelLoadItems4", typeof(TestItem1));
            p1.AddRowLimit(_DBTypesFactory.DatabaseType, 2000);
            queries.Add(p1);

            IObjectLoader loader = _DBTypesFactory.CreateObjectLoader();
            IList<ilist> data = loader.ParallelLoadItems(queries);

            // demonstrates that the list is in the same order 
            // and how to cast the collection for use
            IList<testitem2> items = (IList<testitem2>)data[2];
            items[2].StringData = "Found it!";
        }

步骤 9:问题规划

此方法将演示其中一个 SQL 查询中的错误,以及如何隔离问题查询并帮助您解决问题。 查询 2 有一个明显的错误,旨在帮助演示运行多个查询时隔离问题。

请注意,为错误查询传入的 SQL 标签是“my query 2”,ORM 会在运行查询时将其包含在任何错误中。 如果您在“int a = 1;”行添加一个断点,它将停在那里。

        public static void ParallelLoadItemsError()
        {
            try
            {
                IList<isqlquery> queries = new List<isqlquery>();

                ISqlQuery s1 = _DBTypesFactory.CreateSqlQuery("Select * 
                from TestItem1", "my query 1", typeof(TestItem1));
                s1.AddRowLimit(_DBTypesFactory.DatabaseType, 2000);
                queries.Add(s1);

                ISqlQuery e1 = _DBTypesFactory.CreateSqlQuery("Select  FakeCol1, 
                FakeCol2 from TestItem1", "my query 2", typeof(TestItem1));
                queries.Add(e1);

                ISqlQuery a1 = _DBTypesFactory.CreateSqlQuery("Select * 
                from TestItem2", "my query 3", typeof(TestItem2));
                a1.AddRowLimit(_DBTypesFactory.DatabaseType, 2000);
                queries.Add(a1);

                ISqlQuery p1 = _DBTypesFactory.CreateSqlQuery("Select * 
                from TestItem1", "my query 4", typeof(TestItem1));
                p1.AddRowLimit(_DBTypesFactory.DatabaseType, 2000);
                queries.Add(p1);

                IObjectLoader loader = _DBTypesFactory.CreateObjectLoader();
                IList<ilist> data = loader.ParallelLoadItems(queries);
            }
            catch (Exception ex)
            {
                if (ex.InnerException.InnerException.Message.Contains("my query 2") == true)
                {
                      int a = 1;
                }
            }
        }

步骤 10:添加对并行方法的调用

将以下方法调用添加到“Main”方法的末尾。

// perform parallel load
ParallelLoadItems();

// perform parallel load with a error
ParallelLoadItemsError();

关注点

本文仅触及了“共生”ORM 功能的表面。 有关更高级功能和示例的详细信息,请下载 nuget 包并查看包文件夹中的示例项目。

还有一个配套应用程序可以为现有数据库创建 POCO 类

历史

  • 2019 年 6 月 27 日:初始版本
© . All rights reserved.