흔적이 말끔하다.NET 소스 코드 - 소개, 동적 조회

16610 단어 dapperdotnet
Github 링크: https://github.com/shps951023/Trace-Dapper.NET-Source-Code

1. 머리말


업계의 베테랑과 Stack Overflow의 다년간의 홍보를 통해'Dapper with Entity Framework'는 강력한 조합으로 “safe, convenient, efficient, maintainable”의 수요를 충족시킬 수 있다.
그러나 현재의 인터넷 글에는 짧고 간결한 글이 많지만 어떻게 사용하는지에 머물러 원본 코드의 논리를 체계적으로 해석하는 사람이 없다.따라서 이 글은'Trace Dapper Source Code'라는 글로 Dapper 코드를 깊이 있게 이해하고 디자인의 세부 사항, 효율적인 원칙을 이해하며 업무 수행에서의 실제 응용을 이해하고자 합니다.

2. 설치 환경

  • 부터Dapper's Github
  • 클론 최신 버전
  • 생성Net Core Console 프로젝트

  • 설치NuGet SqlClient 및 Dapper 프로젝트 참조 추가

  • 인터럽트가 있는 컨트롤러를 실행하면 실행할 때 논리를 볼 수 있습니다.

  • 내 개인 환경
  • MSSQLLOCALDB
  • 비소 스튜디오 2019
  • 린파드5
  • 간결한 버전: V2.0.30
  • ILSpy
  • Windows 10 pro
  • 3. 동적 조회


    Dapper dynamic Query를 사용하면 개발 초기 단계에서 클래스 속성을 수정하는 시간을 절약할 수 있습니다. 왜냐하면 테이블 구조가 여전히 in the adjustment stage 이거나, 클래스의 경량급 수요를 설명하는 데 별도의 정력을 들일 필요가 없기 때문입니다.
    테이블이 안정되었을 때 POCO 생성기를 사용하여 클래스를 신속하게 생성하고 이를 강력한 유형의 유지보수로 전환합니다. 예를 들어 PocoClassGenerator.

    왜 Dapper가 이렇게 편리하고 동적을 지원합니까?


    추적 조회 방법의 원본 코드를 통해 두 가지 관건을 찾을 수 있다
  • 실체류는 실제로DapperRow 은식으로 동적으로 전환된다.

  • DapperRow 상속IDynamicMetaObjectProviderand을 받아 해당하는 방법을 실현한다.

  • 이러한 논리에 대해 저는 간단한 버전의 Dapper dynamic Query를 만들어서 독자들이 전환 논리를 이해하도록 하겠습니다.
  • dynamic 유형 변수를 만들고 실체 유형은 ExpandoObject입니다.
  • 상속 관계로 전환IDictionary<string, object>
  • DataReader를 사용하여 GetName을 사용하여 필드 이름을 가져오고 field index에서 값을 얻으며 키와 값
  • 으로 사전에 추가합니다.
  • expandobject는 동적 변환이 가능한 IDynamicMetaObjectProvider 인터페이스를 가지고 있기 때문에
  • public static class DemoExtension
    {
      public static IEnumerable<dynamic> Query(this IDbConnection cnn, string sql)
      {
        using (var command = cnn.CreateCommand())
        {
          command.CommandText = sql;
          using (var reader = command.ExecuteReader())
          {
            while (reader.Read())
            {
              yield return reader.CastToDynamic();
            }
          }
        }
      }
    
      private static dynamic CastToDynamic(this IDataReader reader)
      {
        dynamic e = new ExpandoObject();
        var d = e as IDictionary<string,object>;
        for (int i = 0; i < reader.FieldCount; i++)
          d.Add(reader.GetName(i),reader[i]);
        return e;
      }
    }
    
    현재 우리는 간단한 expandobject 동적 조회 예시의 개념을 이해했다. Dapper가 세부 사항을 어떻게 처리하는지, 그리고 왜 Dapper가 다이나믹 MetaObject Provider를 맞춤형으로 만들어야 하는지 깊이 있게 이해해 주십시오.
    먼저 동적 질의 프로세스 논리를 학습합니다.
    코드:
    using (var cn = new SqlConnection(@"Data Source=(localdb)\MSSQLLocalDB;Integrated Security=SSPI;Initial Catalog=master;"))
    {
        var result = cn.Query("select N'Wei' Name,26 Age").First();
        Console.WriteLine(result.Name);
    }
    
    이 프로세스의 가치는 다음과 같습니다.
    생성 동적 함수 > 캐시에 저장 > 사용 result.Name > 호출로 전송 ((DapperRow)result)["Name"] > DapperTable.Values Array 에서 index value corresponding to the field "Name" in the Values array 로 값을 가져옵니다.
    그리고 GetDapper Row Deserializer 방법의 원본 코드를 보십시오. 이 방법은 동적 운행의 논리를 제어하고, 고위층 API 호출과 캐시 재사용을 위해 동적으로 Func로 생성됩니다.

    Func 로직의 이 섹션:
  • DapperTable는 방법에서 국부 변수이지만 생성된Func 인용이기 때문에 GC가 아니라 메모리에 저장되어 다시 사용됩니다.

  • 동적이기 때문에 유형 매핑을 고려할 필요가 없다. 여기서 직접 사용GetValue(index)으로 데이터베이스에서 값을 얻는다.
  • var values = new object[select columns count];
    for (int i = 0; i < values.Length; i++)
    {
        object val = r.GetValue(i);
        values[i] = val is DBNull ? null : val;
    }
    
  • DapperRow에 데이터 저장
  • public DapperRow(DapperTable table, object[] values)
    {
        this.table = table ?? throw new ArgumentNullException(nameof(table));
        this.values = values ?? throw new ArgumentNullException(nameof(values));
    }
    
  • Dapper Row는 IDynamic MetaObject Provider를 계승하고 GetMetaObject 방법을 실현했다.논리 구현은 DapperRowMetaObject 객체로 돌아갑니다.
  • private sealed partial class DapperRow : System.Dynamic.IDynamicMetaObjectProvider
    {
        DynamicMetaObject GetMetaObject(Expression parameter)
        {
            return new DapperRowMetaObject(parameter, System.Dynamic.BindingRestrictions.Empty, this);
        }
    }
    
  • Dapper RowMetaObject의 주요 기능은 행위를 정의하는 것이다. 다시 쓰기BindSetMember、BindGetMember 방법으로 Dapper는 Get을 정의하고 행위 집합IDictionary<string, object> - GetItem을 사용한다DapperRow - SetValue.

  • 마지막으로 Dapper는 DataReadercolumn order를 사용하고 먼저 열 이름으로 색인을 얻은 다음에 색인과 값을 사용한다.

  • 왜 IDictionary를 계승해야 합니까?


    질문이 하나 있습니다. Dapper RowMetaObject에서 Get과Set 행동을 스스로 정의할 수 있기 때문에 Dictionary GetItem 방법을 사용하지 않고 다른 방법을 사용하지 않습니다. 이것은 you don't need to inherit IDictionary<string,object> 를 의미하는 것입니까?
    Dapper가 이렇게 하는 이유 중 하나는 개방 원칙과 관련이 있다.Dapper Table와 Dapper Row는 모두 저급 실현 유형이다.개폐 원리에 따르면 이들은 should not be opened to users이기 때문에 private로 설정되었다.
    private class DapperTable{/*...*/}
    private class DapperRow :IDictionary<string, object>, IReadOnlyDictionary<string, object>,System.Dynamic.IDynamicMetaObjectProvider{/*...*/}
    
    사용자가 필드 이름을 알고 싶으면 어떻게 합니까?
    Dapper Row는 IDictionary를 실현했기 때문에 upcasting부터 IDictionary<string, object>까지 필드 데이터를 가져올 수 있고 public interface를 통해 필드 데이터를 얻을 수 있습니다.
    public interface IDictionary<TKey, TValue> : ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>, IEnumerable{/*..*/}
    
    예를 들어, 나는 HtmlTableHelper라는 도구를 만들었는데, 이 기능을 사용하여 간결한 동적 조회를 아래 코드와 그림 같은 표 Html로 자동으로 변환한다
    using (var cn = "Your Connection")
    {
      var sourceData = cn.Query(@"select 'ITWeiHan' Name,25 Age,'M' Gender");
      var tablehtml = sourceData.ToHtmlTable(); //Result : <table><thead><tr><th>Name</th><th>Age</th><th>Gender</th></tr></thead><tbody><tr><td>ITWeiHan</td><td>25</td><td>M</td></tr></tbody></table>
    }
    

    좋은 웹페이지 즐겨찾기