.NET에서 Dapper로 데이터베이스 연결을 어떻게 처리합니까?


86

Dapper를 가지고 놀았지만 데이터베이스 연결을 처리하는 가장 좋은 방법을 모르겠습니다.

대부분의 예제는 예제 클래스 또는 각 메서드에서 생성되는 연결 개체를 보여줍니다. 그러나 web.config에서 가져 오는 경우에도 모든 clss에서 연결 문자열을 참조하는 것이 잘못되었습니다.

내 경험은 DbDataContext또는 DbContextLinq to SQL 또는 Entity Framework를 사용하여 왔 으므로 이것은 나에게 새로운 것입니다.

Dapper를 데이터 액세스 전략으로 사용할 때 웹 앱을 어떻게 구성합니까?


너무 늦었지만; 다음과 같이 구현했습니다. stackoverflow.com/a/45029588/5779732
Amit Joshi

사용-날씬한-비동기 적으로 -에 - ASP-NET-코어 2 - exceptionnotfound.net/...
히말라야 Garg를

답변:


54

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

모범 사례를 올바르게 사용하고 있는지 확실하지 않지만 여러 연결 문자열 을 처리하기 위해 이렇게하고 있습니다.

연결 문자열이 하나만 있으면 쉽습니다.

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);
        }

        // ......
    }
}

연결 문자열이 두 개 이상인 경우 문제

Dapper활용 하므로 IDbConnection서로 다른 데이터베이스 연결을 구별하는 방법을 생각해야합니다.

IDbConnection다른 데이터베이스 연결에 해당하는 에서 '상속'된 여러 인터페이스를 만들고 SqlConnection에 다른 데이터베이스 연결 문자열을 삽입 하려고 했습니다 Startup.

실패 때문 SqlConnection로부터 상속 DbConnectionDbConnectioninplements뿐만 IDbConnection아니라 Component클래스입니다. 따라서 사용자 정의 인터페이스는 표현만을 사용할 수 없습니다 SqlConnection.

또한 DbConnection다른 연결 문자열 을 사용하는 자체 클래스 를 만들려고했습니다 . DbConnection클래스의 모든 메서드를 구현해야하므로 너무 복잡합니다 . 에서 도움을 잃었습니다 SqlConnection.

내가하는 일

  1. 동안 Startup모든 연결 문자열 값을 사전에로드했습니다. 또한 enum매직 문자열을 피하기 위해 모든 데이터베이스 연결 이름에 대해을 만들었습니다 .
  2. 사전을 Singleton으로 삽입했습니다.
  3. 주입하는 대신 모든 저장소에 대해 Transient를 IDbConnection만들고 IDbConnectionFactory주입했습니다. 이제 모든 리포지토리 IDbConnectionFactoryIDbConnection.
  4. 언제 올바른 연결을 선택해야합니까? 모든 저장소의 생성자에서! 깔끔하게 만들기 위해 저장소 기본 클래스를 만들고 저장소가 기본 클래스에서 상속 받도록했습니다. 올바른 연결 문자열 선택은 기본 클래스에서 발생할 수 있습니다.

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-나만의 팩토리 구현

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);
        }
    }
}

그런 다음 다른 연결과 통신해야하는 다른 저장소에 대해 다른 저장소 기본 클래스를 만들 수 있습니다.

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);
        }

        // ......
    }
}

이 모든 도움을 바랍니다.


정확히 내가 찾고있는 것. 나는 똑같은 문제가 있었고 같은 방식으로 그것을 해결했지만 이것이 좋은 관행인지는 아직 모르겠지만 내 생각에는 그렇게 생각합니다.
에베 톤

1
IServiceProvider 범위에 IDbConnection을 등록하는 것이 더 낫습니까? 서비스를 생성하고 다른 연결을 사용하여 단일 범위 팩토리로 등록하고 var scope = factory.CreateNonDefaultScope (); var connection = scope.ServiceProvider.GetRequiredService <IDbConnection> ()을 사용하면 기본이 아닌 연결을 얻을 수 있습니다. 상속이 적
으면

이것이 제가 찾고있는 것입니다. @David @Awsome 직업. 감사합니다
Shashwat 프라 카쉬

27

구성에서 연결 문자열을 검색하는 속성을 사용하여 확장 메서드를 만들었습니다. 이렇게하면 호출자가 연결이 열려 있는지 닫혀 있는지 여부 등 연결에 대해 알 필요가 없습니다.이 방법은 Dapper 기능 중 일부를 숨기고 있기 때문에 약간 제한되지만 우리의 매우 간단한 앱에서는 잘 작동합니다. , 그리고 Dapper에서 더 많은 기능이 필요한 경우 항상이를 노출하는 새로운 확장 메서드를 추가 할 수 있습니다.

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
여기에 한 가지 질문이 있습니다. conn.Query가 IEnumerable <T>를 반환하므로 연결 개체를 즉시 삭제하는 것이 안전합니까? IEnumerable은 요소를 읽을 때 구체화하기 위해 연결이 필요하지 않습니까? ToList ()를 실행해야합니까?
Adrian Nasui

확인하려면 Dapper로 다시 돌아 가야하지만 프로덕션 코드에서이 패턴을 그대로 가져 왔을 것입니다. 괜찮을 것입니다. 물론 인터넷에서 모든 코드를 테스트해야합니다.
Shawn Hubbard

2
깔끔한 쿼리 확장 메서드를 사용하는 경우 메서드 자체에서 수행되므로 명시 적으로 연결을 열 필요가 없습니다.
h-rai

4
위 코드의 문제는 buffered : true를 Query 메서드에 전달하면 데이터가 반환되기 전에 연결이 삭제된다는 것입니다. 내부적으로 Dapper는 반환하기 전에 열거 형을 목록으로 변환합니다.
Brian Vallelunga

@BrianVallelunga 그게 아닐까요 buffered: false?
Jodrell

26

약 4 년 전에 질문을 받았지만 어쨌든 대답은 여기 누군가에게 유용 할 것입니다.

나는 모든 프로젝트에서 이렇게한다. 먼저 다음과 같은 몇 가지 도우미 메서드를 포함하는 기본 클래스를 만듭니다.

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;
    }
}

그리고 이러한 기본 클래스가 있으면 상용구 코드 없이도 실제 리포지토리를 쉽게 만들 수 있습니다.

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...
}

따라서 Dapper, SqlConnection-s 및 기타 데이터베이스 액세스 항목과 관련된 모든 코드는 한곳 (BaseRepository)에 있습니다. 모든 실제 리포지토리는 깨끗하고 간단한 단선 방법입니다.

누군가를 도울 수 있기를 바랍니다.


2
BaseRepository공용 또는 추상 메서드 또는 속성을 제공하지 않으므로 불필요한 상속입니다. 대신 DBHelper클래스가 될 수 있습니다 .
Josh Noe

CreateConnection자신의 수업 으로 이동하는 것이 더 좋을까요?
hellboy apr

아마도 ...하지만 개인적으로 저는 모든 것을 단순하게 유지하는 것을 좋아합니다. CreateConnection (...)에 많은 논리가 있다면 좋은 생각 일 수 있습니다. 내 프로젝트에서이 메서드는 "return new Connection (connectionString)"만큼 간단하므로 별도의 CreateConnection (...) 메서드없이 인라인으로 사용할 수 있습니다.
Pavel Melnikov

1
또한 nick-s가 지적했듯이 최신 버전의 Dapper에서는 데이터베이스 연결을 수동으로 열 필요가 없습니다. Dapper가 자동으로 열어줍니다. 게시물을 업데이트했습니다.
Pavel Melnikov

imo를 주입하십시오. services.AddScoped<IDbConnection>(p => new SqlConnection(connString)그런 다음 필요한 곳에 요청하십시오
Sinaesthetic

8

나는 이것을 이렇게한다 :

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 });
        }
    }
}

그런 다음 종속성 (예 : Global.asax.cs 또는 Startup.cs)을 연결할 때마다 다음과 같은 작업을 수행합니다.

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

여기에 한 가지 질문이 있습니다. conn.Query가 Ienumerable <T>를 반환하므로 연결을 즉시 삭제하는 것이 안전합니까? IEnumerable은 요소를 읽을 때 구체화하기 위해 연결이 필요하지 않습니까?
Adrian Nasui

1
@AdrianNasui : 현재 Dapper의 기본 동작은 SQL을 실행하고 반환시 전체 판독기를 버퍼링하는 것이므로 IEnumerable<T>이미 구체화되었습니다. buffered: false, yes 를 통과 하면 using블록을 종료하기 전에 출력을 소비해야합니다 .
Jacob Krall

7

모범 사례는 실제로드 된 용어입니다. 나는 DapperDbDataContext 와 같은 스타일 컨테이너를 좋아 합니다. , 트랜잭션 및 기타 도우미 를 연결할 수 있습니다 . CommandTimeout

예를 들면 :

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가 SqlConnection ([[CONN STRING HERE]]) 부분에 대해 더 많이 요구하지 않습니까? 그는 "하지만 모든 클래스에서 연결 문자열을 참조하는 것은 잘못된 느낌입니다 (각 메서드에서도)"라고 말합니다. Dapper 사용자가 연결 생성 측면을 감싸는 패턴을 생성했는지 궁금합니다. 해당 논리를 건조 / 숨 깁니다. (OP에 대한 제쳐두고, Dapper.Rainbow를 사용할 수 있다면 그렇게하십시오 ... 정말 좋습니다!)
ckittel

4

이 시도:

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
솔루션에서 연결 닫기 / 삭제를 어떻게 처리합니까?
jpshook

@JPShook-나는 그가 사용하고 있다고 믿습니다. (ref stackoverflow.com/a/4717859/2133703 )
MacGyver

4

모두가 너무 일찍 연결을 시작하는 것 같습니까? 나는이 같은 질문을했고 여기 소스를 파고 들었다-https: //github.com/StackExchange/dapper-dot-net/blob/master/Dapper/SqlMapper.cs

데이터베이스와의 모든 상호 작용은 연결이 닫혀 있는지 확인하기 위해 연결을 확인하고 필요에 따라 엽니 다. 이로 인해 conn.open ()없이 위와 같은 구문을 사용하기 만하면됩니다. 이렇게하면 가능한 한 상호 작용에 가깝게 연결이 열립니다. 눈치 채면 즉시 연결이 종료됩니다. 이것은 또한 폐기 중에 자동으로 닫히는 것보다 빠릅니다.

위의 저장소에서 이에 대한 많은 예 중 하나 :

    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();
        }
    }

다음은 DapperWrapper라는 Dapper 용 Wrapper를 사용하는 방법에 대한 간단한 예입니다. 이를 통해 Dapper 및 Simple Crud 메서드를 모두 래핑하여 연결을 관리하고 보안, 로깅 등을 제공 할 수 있습니다.

  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
이것은 Dapper가 연결을 가져올 때 이미 열려있는 경우 연결을 열어 두는 것을 아는 데 매우 유용합니다. 이제 Dapper와 함께 사용하기 전에 db 연결을 미리 열고 있으며 성능이 6 배 향상되었습니다. 감사합니다!
Chris Smith

2

도우미 클래스와의 연결을 래핑합니다.

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
}

사용 예 :

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 });
        });
    }
}

따라서 매번 명시 적으로 연결을 열 필요가 없습니다. 또한 향후 리팩토링의 편의를 위해 이러한 방식으로 사용할 수 있습니다.

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 });
});

이 답변TableName<T>() 에서 무엇을 찾을 수 있습니다 .


0

안녕하세요 @donaldhughes 저도 처음 사용하고 있습니다. 1-연결 문자열을 가져올 클래스 만들기 2-연결 문자열 클래스를 Using

보기:

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);
            }
        }
     }

그리고 잘 작동합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.