Làm cách nào để xử lý Kết nối cơ sở dữ liệu với Dapper trong .NET?


83

Tôi đã chơi với Dapper, nhưng tôi không chắc về cách tốt nhất để xử lý kết nối cơ sở dữ liệu.

Hầu hết các ví dụ cho thấy đối tượng kết nối đang được tạo trong lớp mẫu hoặc thậm chí trong mỗi phương thức. Nhưng tôi cảm thấy sai khi tham chiếu một chuỗi kết nối trong mọi clss, ngay cả khi nó lấy từ web.config.

Kinh nghiệm của tôi đã gắn bó với cách sử dụng một DbDataContexthoặc DbContextvới LINQ to SQL hay Entity Framework, vì vậy đây là mới đối với tôi.

Làm cách nào để cấu trúc các ứng dụng web của tôi khi sử dụng Dapper làm chiến lược Truy cập dữ liệu?


Quá muộn nhưng; Tôi đã triển khai nó như thế này: stackoverflow.com/a/45029588/5779732
Amit Joshi

sử dụng-đoan trang-không đồng bộ-in-asp-net-core-2 - exceptionnotfound.net/...
Himalaya Garg

Câu trả lời:


48

Microsoft.AspNetCore.All : v2.0.3 | Dapper : v1.50.2

Tôi không chắc liệu mình có đang sử dụng các phương pháp hay nhất một cách chính xác hay không, nhưng tôi đang làm theo cách này, để xử lý nhiều chuỗi kết nối.

Thật dễ dàng nếu bạn chỉ có 1 chuỗi kết nối

Startup.cs

using System.Data;
using System.Data.SqlClient;

namespace DL.SO.Project.Web.UI
{
    public class Startup
    {
        public IConfiguration Configuration { get; private set; }

        // ......

        public void ConfigureServices(IServiceCollection services)
        {
            // Read the connection string from appsettings.
            string dbConnectionString = this.Configuration.GetConnectionString("dbConnection1");

            // Inject IDbConnection, with implementation from SqlConnection class.
            services.AddTransient<IDbConnection>((sp) => new SqlConnection(dbConnectionString));

            // Register your regular repositories
            services.AddScoped<IDiameterRepository, DiameterRepository>();

            // ......
        }
    }
}

DiameterRepository.cs

using Dapper;
using System.Data;

namespace DL.SO.Project.Persistence.Dapper.Repositories
{
    public class DiameterRepository : IDiameterRepository
    {
        private readonly IDbConnection _dbConnection;

        public DiameterRepository(IDbConnection dbConnection)
        {
            _dbConnection = dbConnection;
        }

        public IEnumerable<Diameter> GetAll()
        {
            const string sql = @"SELECT * FROM TABLE";

            // No need to use using statement. Dapper will automatically
            // open, close and dispose the connection for you.
            return _dbConnection.Query<Diameter>(sql);
        }

        // ......
    }
}

Sự cố nếu bạn có nhiều hơn 1 chuỗi kết nối

Kể từ khi Dappersử dụngIDbConnection , bạn cần nghĩ ra cách để phân biệt các kết nối cơ sở dữ liệu khác nhau.

Tôi đã cố gắng tạo nhiều giao diện, được 'kế thừa' từ IDbConnection, tương ứng với các kết nối cơ sở dữ liệu khác nhau và chèn SqlConnectioncác chuỗi kết nối cơ sở dữ liệu khác nhau vào Startup.

Điều đó không thành công vì SqlConnectionkế thừa từ DbConnectionDbConnectioninplements không chỉ IDbConnectionmà còn cả Componentlớp. Vì vậy, các giao diện tùy chỉnh của bạn sẽ không thể chỉ sử dụng SqlConnectionimplenentation.

Tôi cũng đã cố gắng tạo DbConnectionlớp của riêng mình có chuỗi kết nối khác nhau. Điều đó quá phức tạp vì bạn phải triển khai tất cả các phương thức từ DbConnectionlớp. Bạn đã mất sự giúp đỡ từ SqlConnection.

Tôi rốt cuộc đang làm gì

  1. Trong khi đó Startup, tôi đã tải tất cả các giá trị chuỗi kết nối vào một từ điển. Tôi cũng tạo một enumcho tất cả các tên kết nối cơ sở dữ liệu để tránh các chuỗi ma thuật.
  2. Tôi đã tiêm từ điển là Singleton.
  3. Thay vì tiêm IDbConnection, tôi đã tạo IDbConnectionFactoryvà tiêm nó dưới dạng Tạm thời cho tất cả các kho. Bây giờ tất cả các kho lưu trữ IDbConnectionFactorythay vì IDbConnection.
  4. Khi nào chọn kết nối phù hợp? Trong hàm tạo của tất cả các kho! Để làm cho mọi thứ sạch sẽ, tôi đã tạo các lớp cơ sở của kho lưu trữ và để các kho kế thừa từ các lớp cơ sở. Việc lựa chọn chuỗi kết nối phù hợp có thể xảy ra trong các lớp cơ sở.

DatabaseConnectionName.cs

namespace DL.SO.Project.Domain.Repositories
{
    public enum DatabaseConnectionName
    {
        Connection1,
        Connection2
    }
}

IDbConnectionFactory.cs

using System.Data;

namespace DL.SO.Project.Domain.Repositories
{
    public interface IDbConnectionFactory
    {
        IDbConnection CreateDbConnection(DatabaseConnectionName connectionName);
    }
}

DapperDbConenctionFactory - triển khai nhà máy của riêng tôi

namespace DL.SO.Project.Persistence.Dapper
{
    public class DapperDbConnectionFactory : IDbConnectionFactory
    {
        private readonly IDictionary<DatabaseConnectionName, string> _connectionDict;

        public DapperDbConnectionFactory(IDictionary<DatabaseConnectionName, string> connectionDict)
        {
            _connectionDict = connectionDict;
        }

        public IDbConnection CreateDbConnection(DatabaseConnectionName connectionName)
        {
            string connectionString = null;
            if (_connectDict.TryGetValue(connectionName, out connectionString))
            {
                return new SqlConnection(connectionString);
            }

            throw new ArgumentNullException();
        }
    }
}

Startup.cs

namespace DL.SO.Project.Web.UI
{
    public class Startup
    {
        // ......

        public void ConfigureServices(IServiceCollection services)
        {
            var connectionDict = new Dictionary<DatabaseConnectionName, string>
            {
                { DatabaseConnectionName.Connection1, this.Configuration.GetConnectionString("dbConnection1") },
                { DatabaseConnectionName.Connection2, this.Configuration.GetConnectionString("dbConnection2") }
            };

            // Inject this dict
            services.AddSingleton<IDictionary<DatabaseConnectionName, string>>(connectionDict);

            // Inject the factory
            services.AddTransient<IDbConnectionFactory, DapperDbConnectionFactory>();

            // Register your regular repositories
            services.AddScoped<IDiameterRepository, DiameterRepository>();

            // ......
        }
    }
}

DiameterRepository.cs

using Dapper;
using System.Data;

namespace DL.SO.Project.Persistence.Dapper.Repositories
{
    // Move the responsibility of picking the right connection string
    //   into an abstract base class so that I don't have to duplicate
    //   the right connection selection code in each repository.
    public class DiameterRepository : DbConnection1RepositoryBase, IDiameterRepository
    {
        public DiameterRepository(IDbConnectionFactory dbConnectionFactory)
            : base(dbConnectionFactory) { }

        public IEnumerable<Diameter> GetAll()
        {
            const string sql = @"SELECT * FROM TABLE";

            // No need to use using statement. Dapper will automatically
            // open, close and dispose the connection for you.
            return base.DbConnection.Query<Diameter>(sql);
        }

        // ......
    }
}

DbConnection1RepositoryBase.cs

using System.Data;
using DL.SO.Project.Domain.Repositories;

namespace DL.SO.Project.Persistence.Dapper
{
    public abstract class DbConnection1RepositoryBase
    {
        public IDbConnection DbConnection { get; private set; }

        public DbConnection1RepositoryBase(IDbConnectionFactory dbConnectionFactory)
        {
            // Now it's the time to pick the right connection string!
            // Enum is used. No magic string!
            this.DbConnection = dbConnectionFactory.CreateDbConnection(DatabaseConnectionName.Connection1);
        }
    }
}

Sau đó, đối với các kho lưu trữ khác cần giao tiếp với các kết nối khác, bạn có thể tạo một lớp cơ sở kho lưu trữ khác cho chúng.

using System.Data;
using DL.SO.Project.Domain.Repositories;

namespace DL.SO.Project.Persistence.Dapper
{
    public abstract class DbConnection2RepositoryBase
    {
        public IDbConnection DbConnection { get; private set; }

        public DbConnection2RepositoryBase(IDbConnectionFactory dbConnectionFactory)
        {
            this.DbConnection = dbConnectionFactory.CreateDbConnection(DatabaseConnectionName.Connection2);
        }
    }
}

using Dapper;
using System.Data;

namespace DL.SO.Project.Persistence.Dapper.Repositories
{
    public class ParameterRepository : DbConnection2RepositoryBase, IParameterRepository
    {
        public ParameterRepository (IDbConnectionFactory dbConnectionFactory)
            : base(dbConnectionFactory) { }

        public IEnumerable<Parameter> GetAll()
        {
            const string sql = @"SELECT * FROM TABLE";
            return base.DbConnection.Query<Parameter>(sql);
        }

        // ......
    }
}

Hy vọng tất cả những sự giúp đỡ.


Chính xác những gì tôi đang tìm kiếm. Tôi đã gặp vấn đề tương tự và giải quyết nó theo cách tương tự, tôi vẫn không biết liệu đây có phải là một cách thực hành tốt hay không, nhưng theo ý kiến ​​của tôi, tôi nghĩ là như vậy.
Ewerton

1
Sẽ tốt hơn nếu đăng ký IDbConnection cho phạm vi IServiceProvider? Người ta có thể tạo dịch vụ và đăng ký dưới dạng nhà máy sản xuất phạm vi singleton với các kết nối khác nhau và sử dụng var scope = factory.CreateNonDefaultScope (); bằng cách sử dụng var connection = scope.ServiceProvider.GetRequiredService <IDbConnection> (), bạn sẽ nhận được kết nối không mặc định của mình. Thừa kế ít hơn cũng sẽ giúp mở rộng khả năng mở rộng ...
quá

27

Tôi đã tạo các phương thức mở rộng có thuộc tính truy xuất chuỗi kết nối từ cấu hình. Điều này cho phép người gọi không phải biết bất kỳ điều gì về kết nối, cho dù nó đang mở hay đóng, v.v. Phương pháp này hạn chế bạn một chút vì bạn đang ẩn một số chức năng Dapper, nhưng trong ứng dụng khá đơn giản của chúng tôi, nó hoạt động tốt cho chúng tôi và nếu chúng tôi cần thêm chức năng từ Dapper, chúng tôi luôn có thể thêm một phương thức mở rộng mới để hiển thị nó.

internal static string ConnectionString = new Configuration().ConnectionString;

    internal static IEnumerable<T> Query<T>(string sql, object param = null)
    {
        using (SqlConnection conn = new SqlConnection(ConnectionString))
        {
            conn.Open();
            return conn.Query<T>(sql, param);
        }
    }

    internal static int Execute(string sql, object param = null)
    {
        using (SqlConnection conn = new SqlConnection(ConnectionString))
        {
            conn.Open();
            return conn.Execute(sql, param);
        }
    }

1
Một câu hỏi ở đây. Vì conn.Query trả về IEnumerable <T> có an toàn để loại bỏ ngay đối tượng kết nối không? IEnumerable không cần kết nối để hiện thực hóa các phần tử khi chúng được đọc? Chúng ta có nên chạy ToList () không?
Adrian Nasui

Tôi phải quay lại Dapper để xác minh, nhưng tôi khá chắc chắn rằng tôi đã lấy mẫu này như là từ mã sản xuất đang hoạt động. Nó sẽ ổn - nhưng tất nhiên, bạn nên kiểm tra bất kỳ mã nào trên internet.
Shawn Hubbard

1
Nếu bạn đang sử dụng phương thức mở rộng truy vấn dapper, bạn không cần phải mở kết nối một cách rõ ràng vì nó được thực hiện trong chính phương thức.
h-rai

4
Vấn đề với đoạn mã trên là nếu bạn chuyển vào vùng đệm: true vào phương thức Truy vấn, kết nối sẽ bị hủy trước khi dữ liệu được trả về. Trong nội bộ, Dapper sẽ biến có thể liệt kê thành một danh sách trước khi quay trở lại.
Brian Vallelunga

@BrianVallelunga sẽ không phải vậy buffered: false?
Jodrell

24

Nó đã được hỏi khoảng 4 năm trước ... nhưng dù sao, có lẽ câu trả lời sẽ hữu ích cho ai đó ở đây:

Tôi làm điều đó như thế này trong tất cả các dự án. Đầu tiên, tôi tạo một lớp cơ sở chứa một vài phương thức trợ giúp như sau:

public class BaseRepository
{
    protected T QueryFirstOrDefault<T>(string sql, object parameters = null)
    {
        using (var connection = CreateConnection())
        {
            return connection.QueryFirstOrDefault<T>(sql, parameters);
        }
    }

    protected List<T> Query<T>(string sql, object parameters = null)
    {
        using (var connection = CreateConnection())
        {
            return connection.Query<T>(sql, parameters).ToList();
        }
    }

    protected int Execute(string sql, object parameters = null)
    {
        using (var connection = CreateConnection())
        {
            return connection.Execute(sql, parameters);
        }
    }

    // Other Helpers...

    private IDbConnection CreateConnection()
    {
        var connection = new SqlConnection(...);
        // Properly initialize your connection here.
        return connection;
    }
}

Và có một lớp cơ sở như vậy, tôi có thể dễ dàng tạo các kho lưu trữ thực mà không cần bất kỳ mã soạn sẵn nào:

public class AccountsRepository : BaseRepository
{
    public Account GetById(int id)
    {
        return QueryFirstOrDefault<Account>("SELECT * FROM Accounts WHERE Id = @Id", new { id });
    }

    public List<Account> GetAll()
    {
        return Query<Account>("SELECT * FROM Accounts ORDER BY Name");
    }

    // Other methods...
}

Vì vậy, tất cả các mã liên quan đến Dapper, SqlConnection-s và các công cụ truy cập cơ sở dữ liệu khác đều nằm ở một nơi (BaseRepository). Tất cả các kho lưu trữ thực là các phương thức 1 dòng đơn giản và sạch sẽ.

Tôi hy vọng nó sẽ giúp một ai đó.


1
BaseRepositorylà kế thừa không cần thiết vì nó không cung cấp bất kỳ phương thức hoặc thuộc tính công khai hoặc trừu tượng nào. Thay vào đó, đây có thể là một DBHelperlớp học.
Josh Noe

Có thể tốt hơn nếu chuyển CreateConnectionđến lớp học riêng?
hellboy

Có thể là ... Nhưng cá nhân tôi thích giữ mọi thứ đơn giản. Nếu bạn có nhiều logic trong CreateConnection (...) thì đó có thể là một ý kiến ​​hay. Trong các dự án của tôi, phương pháp này đơn giản như "trả về kết nối mới (connectionString)", vì vậy nó có thể được sử dụng nội tuyến mà không có phương thức CreateConnection (...) riêng biệt.
Pavel Melnikov

1
Ngoài ra, như nick-s đã chỉ ra, trong các phiên bản Dapper mới nhất, bạn không cần mở kết nối cơ sở dữ liệu theo cách thủ công. Dapper sẽ tự động mở nó cho bạn. đã cập nhật bài viết.
Pavel Melnikov

tiêm imo nó. services.AddScoped<IDbConnection>(p => new SqlConnection(connString)sau đó chỉ cần yêu cầu nó khi cần thiết
Sinaesthetic

8

Tôi làm như thế này:

internal class Repository : IRepository {

    private readonly Func<IDbConnection> _connectionFactory;

    public Repository(Func<IDbConnection> connectionFactory) 
    {
        _connectionFactory = connectionFactory;
    }

    public IWidget Get(string key) {
        using(var conn = _connectionFactory()) 
        {
            return conn.Query<Widget>(
               "select * from widgets with(nolock) where widgetkey=@WidgetKey", new { WidgetKey=key });
        }
    }
}

Sau đó, bất cứ nơi nào tôi kết nối các phụ thuộc của mình (ví dụ: Global.asax.cs hoặc Startup.cs), tôi làm điều gì đó như:

var connectionFactory = new Func<IDbConnection>(() => {
    var conn = new SqlConnection(
        ConfigurationManager.ConnectionStrings["connectionString-name"];
    conn.Open();
    return conn;
});

Một câu hỏi ở đây. Vì conn.Query trả về Ienumerable <T> có an toàn để hủy bỏ kết nối ngay lập tức không? IEnumerable không cần kết nối để hiện thực hóa các phần tử khi chúng được đọc?
Adrian Nasui

1
@AdrianNasui: Hiện tại, hành vi mặc định của Dapper là thực thi SQL của bạn và chuyển lại bộ đệm cho toàn bộ trình đọc, vì vậy hành vi IEnumerable<T>này đã được hiện thực hóa. Nếu bạn vượt qua buffered: false, có, bạn sẽ cần sử dụng đầu ra trước khi thoát khỏi usingkhối.
Jacob Krall

7

Thực tiễn tốt nhất là một thuật ngữ được tải thực sự. Tôi thích một DbDataContextcontainer kiểu dáng như Dapper.Rainbow quảng cáo. Nó cho phép bạn kết hợpCommandTimeout , giao dịch và những người trợ giúp khác.

Ví dụ:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;

using Dapper;

// to have a play, install Dapper.Rainbow from nuget

namespace TestDapper
{
    class Program
    {
        // no decorations, base class, attributes, etc 
        class Product 
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public string Description { get; set; }
            public DateTime? LastPurchase { get; set; }
        }

        // container with all the tables 
        class MyDatabase : Database<MyDatabase>
        {
            public Table<Product> Products { get; set; }
        }

        static void Main(string[] args)
        {
            var cnn = new SqlConnection("Data Source=.;Initial Catalog=tempdb;Integrated Security=True");
            cnn.Open();

            var db = MyDatabase.Init(cnn, commandTimeout: 2);

            try
            {
                db.Execute("waitfor delay '00:00:03'");
            }
            catch (Exception)
            {
                Console.WriteLine("yeah ... it timed out");
            }


            db.Execute("if object_id('Products') is not null drop table Products");
            db.Execute(@"create table Products (
                    Id int identity(1,1) primary key, 
                    Name varchar(20), 
                    Description varchar(max), 
                    LastPurchase datetime)");

            int? productId = db.Products.Insert(new {Name="Hello", Description="Nothing" });
            var product = db.Products.Get((int)productId);

            product.Description = "untracked change";

            // snapshotter tracks which fields change on the object 
            var s = Snapshotter.Start(product);
            product.LastPurchase = DateTime.UtcNow;
            product.Name += " World";

            // run: update Products set LastPurchase = @utcNow, Name = @name where Id = @id
            // note, this does not touch untracked columns 
            db.Products.Update(product.Id, s.Diff());

            // reload
            product = db.Products.Get(product.Id);


            Console.WriteLine("id: {0} name: {1} desc: {2} last {3}", product.Id, product.Name, product.Description, product.LastPurchase);
            // id: 1 name: Hello World desc: Nothing last 12/01/2012 5:49:34 AM

            Console.WriteLine("deleted: {0}", db.Products.Delete(product.Id));
            // deleted: True 


            Console.ReadKey();
        }
    }
}

15
OP đang hỏi thêm về phần SqlConnection ([[CONN STRING TẠI ĐÂY]]) sao? Anh ấy nói "Nhưng tôi cảm thấy sai khi tham chiếu một chuỗi kết nối trong mọi lớp (thậm chí trong mỗi phương thức)" Tôi nghĩ anh ấy đang tự hỏi liệu người dùng Dapper của chúng tôi có tạo ra một mẫu (các loại) xung quanh việc bao bọc phía tạo kết nối của mọi thứ để KHÔ / ẩn logic đó. (An sang một bên để OP, nếu bạn có thể sử dụng Dapper.Rainbow, làm như vậy ... nó thực sự tốt đẹp!)
ckittel

4

Thử đi:

public class ConnectionProvider
    {
        DbConnection conn;
        string connectionString;
        DbProviderFactory factory;

        // Constructor that retrieves the connectionString from the config file
        public ConnectionProvider()
        {
            this.connectionString = ConfigurationManager.ConnectionStrings[0].ConnectionString.ToString();
            factory = DbProviderFactories.GetFactory(ConfigurationManager.ConnectionStrings[0].ProviderName.ToString());
        }

        // Constructor that accepts the connectionString and Database ProviderName i.e SQL or Oracle
        public ConnectionProvider(string connectionString, string connectionProviderName)
        {
            this.connectionString = connectionString;
            factory = DbProviderFactories.GetFactory(connectionProviderName);
        }

        // Only inherited classes can call this.
        public DbConnection GetOpenConnection()
        {
            conn = factory.CreateConnection();
            conn.ConnectionString = this.connectionString;
            conn.Open();

            return conn;
        }

    }

6
Bạn xử lý việc đóng / hủy kết nối trong giải pháp của mình như thế nào?
jpshook

@JPShook - Tôi tin rằng anh ấy đang sử dụng. (ref stackoverflow.com/a/4717859/2133703 )
MacGyver

4

Mọi người dường như mở kết nối hoàn toàn quá sớm? Tôi đã có cùng câu hỏi này và sau khi tìm hiểu Nguồn ở đây - https://github.com/StackExchange/dapper-dot-net/blob/master/Dapper/SqlMapper.cs

Bạn sẽ thấy rằng mọi tương tác với cơ sở dữ liệu đều kiểm tra kết nối để xem nó có bị đóng hay không và mở nó khi cần thiết. Do đó, chúng tôi chỉ sử dụng các câu lệnh như trên mà không có conn.open (). Bằng cách này, kết nối được mở càng gần tương tác càng tốt. Nếu bạn nhận thấy, nó cũng ngay lập tức đóng kết nối. Điều này cũng sẽ nhanh hơn so với việc nó tự động đóng lại trong quá trình thải bỏ.

Một trong nhiều ví dụ về điều này từ repo ở trên:

    private static int ExecuteCommand(IDbConnection cnn, ref CommandDefinition command, Action<IDbCommand, object> paramReader)
    {
        IDbCommand cmd = null;
        bool wasClosed = cnn.State == ConnectionState.Closed;
        try
        {
            cmd = command.SetupCommand(cnn, paramReader);
            if (wasClosed) cnn.Open();
            int result = cmd.ExecuteNonQuery();
            command.OnCompleted();
            return result;
        }
        finally
        {
            if (wasClosed) cnn.Close();
            cmd?.Dispose();
        }
    }

Dưới đây là một ví dụ nhỏ về cách chúng tôi sử dụng một Wrapper cho Dapper được gọi là DapperWrapper. Điều này cho phép chúng tôi kết hợp tất cả các phương thức Dapper và Simple Crud để quản lý kết nối, cung cấp bảo mật, ghi nhật ký, v.v.

  public class DapperWrapper : IDapperWrapper
  {
    public IEnumerable<T> Query<T>(string query, object param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null)
    {
      using (var conn = Db.NewConnection())
      {
          var results = conn.Query<T>(query, param, transaction, buffered, commandTimeout, commandType);
          // Do whatever you want with the results here
          // Such as Security, Logging, Etc.
          return results;
      }
    }
  }

1
Điều này thực sự hữu ích khi biết rằng Dapper sẽ để kết nối mở nếu nó đã mở khi nó nhận được. Bây giờ tôi đang mở trước kết nối db trước khi vượt qua / sử dụng nó với Dapper và tôi đã đạt được hiệu suất gấp 6 lần - cảm ơn!
Chris Smith

2

Tôi kết nối với lớp trợ giúp:

public class ConnectionFactory
{
    private readonly string _connectionName;

    public ConnectionFactory(string connectionName)
    {
        _connectionName = connectionName;
    }

    public IDbConnection NewConnection() => new SqlConnection(_connectionName);

    #region Connection Scopes

    public TResult Scope<TResult>(Func<IDbConnection, TResult> func)
    {
        using (var connection = NewConnection())
        {
            connection.Open();
            return func(connection);
        }
    }

    public async Task<TResult> ScopeAsync<TResult>(Func<IDbConnection, Task<TResult>> funcAsync)
    {
        using (var connection = NewConnection())
        {
            connection.Open();
            return await funcAsync(connection);
        }
    }

    public void Scope(Action<IDbConnection> func)
    {
        using (var connection = NewConnection())
        {
            connection.Open();
            func(connection);
        }
    }

    public async Task ScopeAsync<TResult>(Func<IDbConnection, Task> funcAsync)
    {
        using (var connection = NewConnection())
        {
            connection.Open();
            await funcAsync(connection);
        }
    }

    #endregion Connection Scopes
}

Ví dụ về cách sử dụng:

public class PostsService
{
    protected IConnectionFactory Connection;

    // Initialization here ..

    public async Task TestPosts_Async()
    {
        // Normal way..
        var posts = Connection.Scope(cnn =>
        {
            var state = PostState.Active;
            return cnn.Query<Post>("SELECT * FROM [Posts] WHERE [State] = @state;", new { state });
        });

        // Async way..
        posts = await Connection.ScopeAsync(cnn =>
        {
            var state = PostState.Active;
            return cnn.QueryAsync<Post>("SELECT * FROM [Posts] WHERE [State] = @state;", new { state });
        });
    }
}

Vì vậy, tôi không phải mở kết nối một cách rõ ràng mọi lúc. Ngoài ra, bạn có thể sử dụng nó theo cách này để thuận tiện cho việc tái cấu trúc trong tương lai:

var posts = Connection.Scope(cnn =>
{
    var state = PostState.Active;
    return cnn.Query<Post>($"SELECT * FROM [{TableName<Post>()}] WHERE [{nameof(Post.State)}] = @{nameof(state)};", new { state });
});

Điều gì TableName<T>()có thể được tìm thấy trong câu trả lời này .


0

Xin chào @donaldhughes Tôi cũng là người mới tham gia và tôi sử dụng để làm việc này: 1 - Tạo một lớp để lấy Chuỗi kết nối của tôi 2 - Gọi lớp chuỗi kết nối trong Sử dụng

Nhìn:

DapperConnection.cs

public class DapperConnection
{

    public IDbConnection DapperCon {
        get
        {
            return new SqlConnection(ConfigurationManager.ConnectionStrings["Default"].ToString());

        }
    }
}

DapperRepository.cs

  public class DapperRepository : DapperConnection
  {
       public IEnumerable<TBMobileDetails> ListAllMobile()
        {
            using (IDbConnection con = DapperCon )
            {
                con.Open();
                string query = "select * from Table";
                return con.Query<TableEntity>(query);
            }
        }
     }

Và nó hoạt động tốt.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.