发布于 2026-01-06 0 阅读
0

C#:是什么让你选择 RepoDb 而不是 Dapper (ORM)?DEV 的全球展示挑战赛,由 Mux 呈现:展示你的项目!

C#:为什么你会选择 RepoDb 而不是 Dapper(ORM)?

由 Mux 赞助的 DEV 全球展示挑战赛:展示你的项目!

介绍

在本页中,我们将分享RepoDbDapper 的区别以及它们各自的独特之处。我们尽力在大多数方面进行一对一的比较。希望本页内容能帮助您作为开发者,有充分的理由选择RepoDb作为您的微型 ORM

“我是一名开源贡献者,今天想和大家分享我的成果。我为此付出了很多努力,旨在改进 .NET 中的数据访问。我恳请大家支持这个库。希望大家能够分享、撰写博客并使用它。”

本教程的所有内容均由我(作者本人)撰写。与我们对RepoDb的了解相比,我们对Dapper 的了解还不够深入。因此,如果您认为本页面内容偏向RepoDb ,请立即提出您的意见建议

在我们开始之前

以下示例中我们使用的编程语言和数据库提供商分别是C#SQL Server

这两个库都是用于.NET的ORM框架。它们都轻量级、快速且高效。Dapper是一个功能齐全的微型 ORM,RepoDb一个混合型 ORM

为了避免比较结果出现偏差,我们将不讨论RepoDb中存在而Dapper中不存在的功能(例如:缓存跟踪查询提示可扩展性语句构建器存储库)(反之亦然)。此外,比较结果也不包含两者的任何其他扩展库(例如:RepoDb.SqLiteRepoDb.MySqlRepoDb.PostgreSqlDapper.ContribDapperExtensionsDapper.SqlBuilder等)。

表格

假设我们有以下数据库表。

CREATE TABLE [dbo].[Customer]
(
    [Id] BIGINT IDENTITY(1,1) 
    , [Name] NVARCHAR(128) NOT NULL
    , [Address] NVARCHAR(MAX)
    , CONSTRAINT [PK_Customer] PRIMARY KEY CLUSTERED ([Id] ASC )
)
ON [PRIMARY];
GO

CREATE TABLE [dbo].[Product]
(
    [Id] BIGINT IDENTITY(1,1) 
    , [Name] NVARCHAR(128) NOT NULL
    , [Price] Decimal(18,2)
    , CONSTRAINT [PK_Product] PRIMARY KEY CLUSTERED ([Id] ASC )
)
ON [PRIMARY];
GO

CREATE TABLE [dbo].[Order]
(
    [Id] BIGINT IDENTITY(1,1) 
    , [ProductId] BIGINT NOT NULL
    , [CustomerId] BIGINT
    , [OrderDateUtc] DATETIME(5)
    , [Quantity] INT
    , CONSTRAINT [PK_Order] PRIMARY KEY CLUSTERED ([Id] ASC )
)
ON [PRIMARY];
GO

模型

假设我们有以下类模型。

public class Customer
{
    public long Id { get; set; }
    public string Name { get; set; }
    public string Address { get; set; }
}

public class Product
{
    public long Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
}

public class Order
{
    public long Id { get; set; }
    public long ProductId { get; set; }
    public long CustomerId { get; set; }
    public int Quantity { get; set; }
    public DateTime OrderDateUtc{ get; set; }
}

CRUD 基本区别

查询多行

潇洒:

  • 询问:

    using (var connection = new SqlConnection(ConnectionString))
    {
        var customers = connection.Query<Customer>("SELECT * FROM [dbo].[Customer];");
    }
    

RepoDb:

  • 原始 SQL:

    using (var connection = new SqlConnection(ConnectionString))
    {
        var customers = connection.ExecuteQuery<Customer>("SELECT * FROM [dbo].[Customer];");
    }
    
  • 流利:

    using (var connection = new SqlConnection(ConnectionString))
    {
        var customers = connection.QueryAll<Customer>();
    }
    

查询单个记录

潇洒:

  • 询问

    using (var connection = new SqlConnection(ConnectionString))
    {
        var customer = connection.Query<Customer>("SELECT * FROM [dbo].[Customer] WHERE (Id = @Id);", new { Id = 10045 }).FirstOrDefault();
    }
    

RepoDb:

  • 原始 SQL:

    using (var connection = new SqlConnection(ConnectionString))
    {
        var customer = connection.ExecuteQuery<Customer>("SELECT * FROM [dbo].[Customer] WHERE (Id = @Id);", new { Id = 10045 }).FirstOrDefault();
    }
    
  • 流利:

    using (var connection = new SqlConnection(ConnectionString))
    {
        var customer = connection.Query<Customer>(e => e.Id == 10045).FirstOrDefault();
    }
    

插入记录

潇洒:

  • 执行:

    默认情况下,它返回受影响的行数。

    using (var connection = new SqlConnection(ConnectionString))
    {
        var customer = new Customer
        {
            Name = "John Doe",
            Address = "New York"
        };
        var affectedRows = connection.Execute("INSERT INTO [dbo].[Customer] (Name, Address) VALUES (@Name, @Address);", customer);
    }
    
  • 询问:

    返回标识值。

    using (var connection = new SqlConnection(ConnectionString))
    {
        var customer = new Customer
        {
            Name = "John Doe",
            Address = "New York"
        };
        var id = connection.Query<long>("INSERT INTO [dbo].[Customer] (Name, Address) VALUES (@Name, @Address); SELECT CONVERT(BIGINT, SCOPE_IDENTITY());", customer).Single();
    }
    

RepoDb:

  • 原始 SQL:

    using (var connection = new SqlConnection(ConnectionString))
    {
        var customer = new Customer
        {
            Name = "John Doe",
            Address = "New York"
        };
        var id = connection.ExecuteScalar<long>("INSERT INTO [dbo].[Customer] (Name, Address) VALUES (@Name, @Address); SELECT CONVERT(BIGINT, SCOPE_IDENTITY());", customer);
    }
    
  • 流利:

    using (var connection = new SqlConnection(ConnectionString))
    {
        var customer = new Customer
        {
            Name = "John Doe",
            Address = "New York"
        };
        var id = (long)connection.Insert<Customer>(customer); // or connection.Insert<Customer, long>(customer);
    }
    

更新记录

潇洒:

  • 执行:

    using (var connection = new SqlConnection(ConnectionString))
    {
        var affectedRows = connection.Execute("UPDATE [dbo].[Customer] SET Name = @Name, Address = @Address WHERE Id = @Id;",
        new
        {
            Id = 10045,
            Name = "John Doe",
            Address = "New York"
        });
    }
    

RepoDb:

  • 原始 SQL:

    using (var connection = new SqlConnection(ConnectionString))
    {
        var affectedRows = connection.ExecuteScalar<int>("UPDATE [dbo].[Customer] SET Name = @Name, Address = @Address WHERE Id = @Id;",
        new
        {
            Id = 10045,
            Name = "John Doe",
            Address = "New York"
        });
    }
    
  • 流利:

    using (var connection = new SqlConnection(ConnectionString))
    {
        var customer = new Customer
        {
            Id = 10045,
            Name = "John Doe",
            Address = "New York"
        };
        var affectedRows = connection.Update<Customer>(customer);
    }
    

删除记录

潇洒:

  • 执行:

    using (var connection = new SqlConnection(ConnectionString))
    {
        var affectedRows = connection.Execute("DELETE FROM [dbo].[Customer] WHERE Id = @Id;", new { Id = 10045 });
    }
    

RepoDb:

  • 原始 SQL:

    using (var connection = new SqlConnection(ConnectionString))
    {
        var affectedRows = connection.ExecuteScalar<int>("DELETE FROM [dbo].[Customer] WHERE Id = @Id;", new { Id = 10045 });
    }
    
  • 流利:

    using (var connection = new SqlConnection(ConnectionString))
    {
        var affectedRows = connection.Delete<Customer>(10045);
    }
    

提前通话的区别

查询父节点及其子节点

假设我们已经在Customer类中添加了Orders(类型为 IEnumerable<Order>)属性

  • 顾客

    public class Customer
    {
        public long Id { get; set; }
        public string Name { get; set; }
        public string Address { get; set; }
        public IEnumerable<Order> Orders { get; set; }
    }
    
  • 命令

    public class Order
    {
        public long Id { get; set; }
        public long ProductId { get; set; }
        public long CustomerId { get; set; }
        public int Quantity { get; set; }
        public DateTime OrderDateUtc{ get; set; }
    }
    

潇洒:

  • 询问:

    using (var connection = new SqlConnection(ConnectionString))
    {
        var sql = "SELECT C.Id, C.Name, C.Address, O.ProductId, O.Quantity, O.OrderDateUtc FROM [dbo].[Customer] C INNER JOIN [dbo].[Order] O ON O.CustomerId = C.Id WHERE C.Id = @Id;";
        var customers = connection.Query<Customer, Order, Customer>(sql,
        (customer, order) =>
        {
            customer.Orders = customer.Orders ?? new List<Order>();
            customer.Orders.Add(order);
            return customer;
        },
        new { Id = 10045 });
    }
    
  • 查询多个:

    using (var connection = new SqlConnection(ConnectionString))
    {
        var sql = "SELECT * FROM [dbo].[Customer] WHERE Id = @CustomerId; SELECT * FROM [dbo].[Order] WHERE CustomerId = @CustomerId;";
        using (var result = connection.QueryMultiple(sql, new { CustomerId = 10045 }))
        {
            var customer = result.Read<Customer>().First();
            var orders = result.Read<Order>().ToList();
        }
    }
    

RepoDb:

目前我们有意暂不支持JOIN功能。我们在“通过 QueryMultiple 和 ExecuteQueryMultiple 处理多个结果集”页面中对此进行了说明。此外,我们也在常见问题解答中提供了相关答案

不过,这项功能的支持工作即将启动。我们目前正在根据社区的反馈进行一项投票调查,探讨如何实现这项功能。您可以在这里查看讨论内容,我们也期待听到您的意见!

这一点毋庸置疑。最理想的方法是在数据库中执行真正的INNER JOIN操作,就像Dapper所做的那样!

然而,在RepoDb中还有另一种方法可以实现这一点。它可以通过多查询来实现,多查询可以在一次调用中执行多个打包的 SELECT 语句。

  • 原始 SQL:

    using (var connection = new SqlConnection(ConnectionString))
    {
        var sql = "SELECT * FROM [dbo].[Customer] WHERE Id = @CustomerId; SELECT * FROM [dbo].[Order] WHERE CustomerId = @CustomerId;";
        var extractor = connection.ExecuteQueryMultiple(sql, new { CustomerId = 10045 });
        var customer = extractor.Extract<Customer>().FirstOrDefault();
        var orders = extractor.Extract<Order>().AsList();
        customer.Orders = orders;
    }
    
  • 流利:

    using (var connection = new SqlConnection(ConnectionString))
    {
        var customerId = 10045;
        var tuple = connection.QueryMultiple<Customer, Order>(customer => customer.Id == customerId, order => order.CustomerId == customerId);
        var customer = tuple.Item1.FirstOrDefault();
        var orders = tuple.Item2.AsList();
        customer.Orders = orders;
    }
    

查询多个父母及其子女

与上一节内容几乎相同。

  • 询问:

    var customers = new List<Customer>();
    using (var connection = new SqlConnection(ConnectionString))
    {
        var sql = "SELECT C.Id, C.Name, C.Address, O.ProductId, O.Quantity, O.OrderDateUtc FROM [dbo].[Customer] C INNER JOIN [dbo].[Order] O ON O.CustomerId = C.Id;";
        var customers = connection.Query<Customer, Order, Customer>(sql,
        (customer, order) =>
        {
            customer = customers.Where(e => e.Id == customer.Id).FirstOrDefault() ?? customer;
            customer.Orders = customer.Orders ?? new List<Order>();
            customer.Orders.Add(order);
            return customer;
        });
    }
    

    注意:这种黑客技术是在开发者端进行的,而不是嵌入在库内部的。

  • 查询多个:

    using (var connection = new SqlConnection(ConnectionString))
    {
        var sql = "SELECT * FROM [dbo].[Customer]; SELECT * FROM [dbo].[Order];";
        using (var result = connection.QueryMultiple(sql, new { CustomerId = 10045 }))
        {
            var customers = result.Read<Customer>().ToList();
            var orders = result.Read<Order>().ToList();
            customers.ForEach(customer =>
                customer.Orders = orders.Where(o => o.CustomerId == customer.Id).ToList()); // Client memory processing
        }
    }
    

RepoDb:

  • 原始 SQL:

    using (var connection = new SqlConnection(ConnectionString))
    {
        var extractor = connection.ExecuteQueryMultiple("SELECT * FROM [dbo].[Customer]; SELECT * FROM [dbo].[Order];");
        var customers = extractor.Extract<Customer>().AsList();
        var orders = extractor.Extract<Order>().AsList();
        customers.ForEach(customer =>
            customer.Orders = orders.Where(o => o.CustomerId == customer.Id).AsList()); // Client memory processing
    }
    
  • 流利:

    using (var connection = new SqlConnection(ConnectionString))
    {
        var customerId = 10045;
        var tuple = connection.QueryMultiple<Customer, Order>(customer => customer.Id == customerId, order => order.CustomerId == customerId);
        var customers = tuple.Item1.FirstOrDefault();
        var orders = tuple.Item2.AsList();
        customers.ForEach(customer =>
            customer.Orders = orders.Where(o => o.CustomerId == customer.Id).AsList()); // Client memory processing
    }
    

插入多行

潇洒:

  • 询问:

    using (var connection = new SqlConnection(ConnectionString))
    {
        var customers = GenerateCustomers(1000);
        var identities = connection.Query<long>("INSERT INTO [dbo].[Customer] (Name, Address) VALUES (@Name, @Address); SELECT CONVERT(BIGINT, SCOPE_IDENTITY());", customers);
    }
    

    实际上,这一点我不太明白:

    • 它是否会创建隐式事务?如果其中一行数据出错会怎样?
    • 它是否遍历列表并多次调用DbCommand.Execute ?

    请在这里纠正我,以便我立即更新此页面。

RepoDb:

  • 批量操作:

    using (var connection = new SqlConnection(ConnectionString))
    {
        var customers = GenerateCustomers(1000);
        var affectedRows = connection.InsertAll<Customer>(customers);
    }
    

    可以通过向batchSize参数传递一个值来批量执行上述操作

    注意:您可以指定要针对的列。此外,标识值会自动设置回实体。

  • 批量操作:

    using (var connection = new SqlConnection(ConnectionString))
    {
        var customers = GenerateCustomers(1000);
        var affectedRows = connection.BulkInsert<Customer>(customers);
    }
    

    可以通过向batchSize参数传递一个值来批量执行上述操作

    注:仅供参考。此操作使用ADO.NETSqlBulkCopy方法。由于这是真正的批量操作,因此不应将其性能与Dapper 的性能进行比较。与Dapper(多条插入)和RepoDbInsertAll)操作相比,此操作速度极快。

合并多行

潇洒:

  • 询问:

    using (var connection = new SqlConnection(ConnectionString))
    {
        var sql = @"MERGE [dbo].[Customer] AS T
            USING
                (SELECT @Name, @Address) AS S
            ON
                S.Id = T.Id
            WHEN NOT MATCH THEN
                INSERT INTO
                (
                    Name
                    , Address
                )
                VALUES
                (
                    S.Name
                    , S.
                Address)
            WHEN MATCHED THEN
                UPDATE
                SET Name = S.Name
                    , Address = S.Address
            OUTPUT INSERTED.Id AS Result;";
        var customers = GenerateCustomers(1000);
        var identities = connection.Query<long>(sql, customers);
    }
    

    这里我的问题和上一节一样。

RepoDb:

  • 流利:

    using (var connection = new SqlConnection(ConnectionString))
    {
        var customers = GenerateCustomers(1000);
        var affectedRows = connection.MergeAll<Customer>(customers);
    }
    

    可以通过向batchSize参数传递一个值来批量执行上述操作

    注意:您可以设置限定字段。此外,对于新插入的记录,标识值会自动设置回实体。

更新多行

潇洒:

  • 询问:

    using (var connection = new SqlConnection(ConnectionString))
    {
        var customers = GenerateCustomers(1000);
        var affectedRows = connection.Execute("UPDATE [dbo].[Customer] SET Name = @Name, Address = @Address WHERE Id = @Id;", customers);
    }
    

RepoDb:

  • 流利:

    using (var connection = new SqlConnection(ConnectionString))
    {
        var customers = GenerateCustomers(1000);
        var affectedRows = connection.UpdateAll<Customer>(customers);
    }
    

    可以通过向batchSize参数传递一个值来批量执行上述操作

    注意:您可以设置限定符字段

批量插入多行

潇洒:

  • ADO.NET:

    using (var connection = new SqlConnection(ConnectionString))
    {
        var customers = GenerateCustomers(1000);
        var table = ConvertToTable(customers);
        using (var sqlBulkCopy = new SqlBulkCopy(connection, options, transaction))
            {
            sqlBulkCopy.DestinationTableName = "Customer";
            sqlBulkCopy.WriteToServer(table);
        }
    }
    

    注意:您也可以传递DbDataReader的实例(而不是DataTable)。

RepoDb:

  • 流利:

    using (var connection = new SqlConnection(ConnectionString))
    {
        var customers = GenerateCustomers(1000);
        var affectedRows = connection.BulkInsert<Customer>(customers);
    }
    

    注意:您也可以传递DbDataReader的实例。

  • 流利(目标明确):

    using (var connection = new SqlConnection(ConnectionString))
    {
        var customers = GenerateCustomers(1000);
        var affectedRows = connection.BulkInsert("[dbo].[Customer]", customers);
    }
    

按批次查询行

潇洒:

  • 询问:

    using (var connection = new SqlConnection(ConnectionString))
    {
        var sql = @"WITH CTE AS
            (
                SELECT TOP (@Rows) ROW_NUMBER() OVER(ORDER BY Name ASC) AS RowNumber
                FROM [dbo].[Customer]
                WHERE (Address = @Address)
            )
            SELECT Id
                , Name
                , Address
            FROM
                CTE
            WHERE
                RowNumber BETWEEN @From AND (@From + @Rows);";
        using (var connection = new SqlConnection(ConnectionString))
        {
            var customers = connection.Query<Customer>(sql, new { From = 0, Rows = 100, Address = "New York" });
        }
    }
    

    注:您也可以使用 ( LIMIT ) 关键字来执行此操作。这取决于您的个人喜好。

RepoDb:

  • 流利:

    using (var connection = new SqlConnection(ConnectionString))
    {
        var customers = connection.BatchQuery<Customer>(e => e.Address == "New York",
            page: 0,
            rowsPerBatch: 100,
            orderBy: OrderField.Parse(new { Name = Order.Ascending }));
    }
    

从不同数据库复制记录

潇洒:

  • 询问:

    using (var sourceConnection = new SqlConnection(SourceConnectionString))
    {
        var customers = sourceConnection.Query<Customer>("SELECT * FROM [dbo].[Customer];");
        using (var destinationConnection = new SqlConnection(DestinationConnectionString))
        {
            var identities = destinationConnection.Query<long>("INSERT INTO [dbo].[Customer] (Name, Address) VALUES (@Name, @Address); SELECT CONVERT(BIGINT, SCOPE_IDENTITY());", customers);
        }
    }
    

RepoDb:

  • Fluent(全部插入):

    using (var sourceConnection = new SqlConnection(SourceConnectionString))
    {
        var customers = sourceConnection.QueryAll<Customer>();
        using (var destinationConnection = new SqlConnection(DestinationConnectionString))
        {
            var affectedRows = destinationConnection.InsertAll<Customer>(customers);
        }
    }
    
  • Fluent(批量插入):

    using (var sourceConnection = new SqlConnection(SourceConnectionString))
    {
        var customers = sourceConnection.QueryAll<Customer>();
        using (var destinationConnection = new SqlConnection(DestinationConnectionString))
        {
            var affectedRows = destinationConnection.BulkInsert<Customer>(customers);
        }
    }
    
  • 流畅(流媒体):

    这是处理大型数据集的最佳且推荐的方法。我们不会在客户端应用程序中将数据作为类对象传递。

    using (var sourceConnection = new SqlConnection(SourceConnectionString))
    {
        using (var reader = sourceConnection.ExecuteReader("SELECT * FROM [dbo].[Customer];"))
        {
            using (var destinationConnection = new SqlConnection(DestinationConnectionString))
            {
                var affectedRows = destinationConnection.BulkInsert<Customer>(reader);
            }
        }
    }
    

    注意:请检查排序规则约束。这是ADO.NET 的特性。

参数传递

潇洒:

  • 动态的:

    Query<T>(sql, new { Id = 10045 });
    

    它始终是相等运算。您可以通过SQL 语句控制查询

  • 动态参数:

    var parameters = new DynamicParameters();
    parameters.Add("Name", "John Doe");
    parameters.Add("Address", "New York");
    Query<T>(sql, parameters);
    

RepoDb:

  • 动态的:

    Query<T>(new { Id = 10045 });
    

    与Dapper类似,它始终指的是相等运算。您可以通过SQL 语句控制查询

  • LINQ表达式:

    Query<T>(e => e.Id == 10045);
    
  • 查询字段:

    Query<T>(new QueryField("Id", 10045));
    
  • 查询字段或查询组:

    var queryFields = new[]
    {
        new QueryField("Name", "John Doe")
        new QueryField("Address", "New York")
    };
    Query<T>(queryFields); // or Query<T>(new QueryGroup(queryFields));
    

参数数组

潇洒:

  • 询问:

    using (var connection = new SqlConnection(ConnectionString))
    {
        var addresses = new [] { "New York", "Washington" };
        var customers = connection.Query<Customer>("SELECT * FROM [dbo].[Customer] WHERE Address IN (@Addresses);", new { Addresses = addresses });
    }
    

RepoDb:

  • 执行查询:

    using (var connection = new SqlConnection(ConnectionString))
    {
        var addresses = new [] { "New York", "Washington" };
        var customers = connection.ExecuteQuery<Customer>("SELECT * FROM [dbo].[Customer] WHERE Address IN (@Addresses);", new { Addresses = addresses });
    }
    

    如需进一步说明,您可以访问我们的文档

  • 询问:

    using (var connection = new SqlConnection(ConnectionString))
    {
        var addresses = new [] { "New York", "Washington" };
        var customers = connection.Query<Customer>(e => addresses.Contains(e => e.Address));
    }
    

表达式树

  • Dapper 不支持Linq 表达式,仅支持动态动态参数
  • RepoDb 支持Linq 表达式动态查询对象

注意: Dapper.DynamicParameters只是RepoDb.QueryObjects的一个子集。QueryObjects具有更强大的功能,可以进一步支持Linq表达式

请查阅这两份文档。

支持的数据库

潇洒:

支持所有关系数据库管理系统(RDBMS)数据提供程序。

RepoDb:

  1. Raw-SQL 支持所有关系数据库管理系统 (RDBMS) 数据提供程序。
  2. Fluent 调用仅支持SQL ServerSqLiteMySqlPostgreSql

性能和效率

我们只参考社区认可的 ORM 基准测试工具之一,即RawDataAccessBencher

.NET Core:

以下是我们根据官方执行结果得出的观察结果。官方结果可在此处查看。

表现:

  • RepoDb 是获取集合记录时速度最快的 ORM,无论是原始 SQL调用还是Fluent调用。
  • Dapper 和 RepoDb 在获取单条记录时的速度相同。
  • 在获取单个记录时,Dapper 比 RepoDb 的Fluent调用速度更快。

效率:

  • RepoDb 是获取集合记录时效率最高的 ORM,支持原始 SQLFluent调用。
  • 在获取单条记录时,Dapper 比 RepoDb 效率高得多。

.NET Framework:

RepoDb 是获取集合记录和单个记录速度最快效率最高的ORM 。官方结果可在此处查看

质量

潇洒:

Dapper 自 2012 年以来一直在运行,并被StackOverflow.com使用。它拥有庞大的用户群,并得到了社区的大力支持。

RepoDb:

我们尽力为每个场景编写了一个测试用例,目前已交付了数千个测试用例(约 6500 个),包括单元测试集成测试。我们希望您也能帮忙审阅一下。

以下是我们的测试套件链接。

我们(或者说作为作者的我)一直被质疑软件质量并不取决于测试的数量。然而,我们坚信,投入大量精力编写测试能够增强库用户(即.NET社区)的信心。实际上,如果有人向我们提交PR ,这有助于我们避免对已正常运行的功能进行手动修改;它还能防止库出现任何意料之外的错误。

质量结论:

两者都质量很高,但Dapper比RepoDb成熟得多。这一点我们并不否认!

图书馆支持

潇洒:

经过验证,并得到 .NET 社区的大力支持;由StackOverflow.com资助。

RepoDb:

该项目由一人独立完成,未获得任何机构的资助或赞助。目前正处于起步阶段,希望得到 .NET 社区的更多支持。

许可和合法性

两者均采用Apache-2.0许可证。

免责声明:

我们并非法律专家,但提供咨询服务。如果RepoDb遇到任何版权或商标方面的纠纷,目前尚未解决。


总体结论

我们希望您能再次考虑并访问这个图书馆。它相比最初的样子已经有了很大的改进。

简单

Dapper 虽然轻量级,但会将你带入代码开发的复杂层面。编写原始 SQL 语句总是很繁琐,而且由于它对编译器不友好,维护起来也很困难。此外,为了完成必要的任务,你还需要实现一些必要的功能。

RepoDb 是一个非常易于使用的 ORM,它具有足够多的功能集供您使用。

表现

如果性能是唯一考虑因素,那么 RepoDb 比 Dapper 快,这足以成为选择该库的理由。

RepoDb 是 .NET 中最快的 ORM。这一说法得到了社区认可的 ORM 性能测试工具RawDataAccessBencher的官方运行结果的支持。

效率

RepoDb 比 Dapper 更高效(与性能部分所述相同)。

经验

使用 RepoDb 开发代码更加轻松快捷。它拥有丰富的功能集,可立即使用(例如:二层缓存、流畅方法)。它将帮助您作为开发人员以更快、更简洁的方式交付更多代码。

特征

在 RepoDb 中,微型 ORM 框架内具备必要的功能,这将对您的开发大有帮助。

批量操作、属性处理器、二级缓存、表达式树、多重查询和内联提示等功能是最常用的功能。而Dapper的主要痛点在于,这些功能在Dapper中缺失。


感谢您阅读本文。原文链接在

我们恳请您支持此代码库和解决方案。您为我们的GitHub页面点赞对我们意义重大。

文章来源:https://dev.to/mikependon/c-what-will-make-you-choose-repodb-over-dapper-orm-3eb8