Dapper 용 SQL 쿼리 생성기

c# dapper orm sql

문제

안녕하세요, 새 프로젝트에서 사용할 최상의 성능을 가진 ORM을 찾으려고했습니다. 나의 최종 선택은 Dapper가되었다. 우리는 또한 Dapper에게 전달할 SQL 쿼리를 하드 코딩하지 못하게하는 다음과 같은 기능을 포함하도록 애플리케이션을 가지고 있어야합니다.

  1. 데이터베이스 독립적
  2. 런타임 엔티티 정의

나는 Dapper를위한 SQL 생성기를 작성하는 것에 대해 생각했지만, 내가 따르고있는 접근법이 최상인지는 확실하지 않다.

  1. Methods의 시그니쳐를 가지는 Interface를 선언합니다. 구현은 사용할 데이터베이스 시스템 (SQL Server / MySQL / PostgreSql / DB2 / Oracle / etc ...)에 해당합니다.
  2. 다음 형식을 사용하여 데이터베이스 XML 스키마를 만듭니다.

    <sqltable name="Foo">
        <sqlfield name="ID" primarykey="1" />
        <sqlfield name="Name" />
        <sqlfield name="Surname />
        <sqlfield name="etc" />
        <sqlreference name"KooID" table="Koo" field="ID" />
    </sqltable>
    
  3. 위에 제공된 XML을 사용하여 클래스 / 엔티티를 생성합니다 (런타임에 스키마의 확장을 허용 함). 생성 된 객체는 POCO입니다.

  4. 현재 엔티티의 속성에 대해 루프를 사용하여 (reflexion 사용) 메소드를 구현하고 property가 null이 아닌 SQL 문을 생성합니다.

    String GetInsert(object currentEntity)
    return:
    "INSERT INTO Foo (ID, Name) VALUES (1, 'BooBoo')"
    
  5. 구현에는 적어도

    SELECT
    INSERT INTO
    UPDATE
    DELETE
    JOIN /*(using references like the KooID above)*/
    WHERE /*(using filter expressions)*/
    

이 접근법의 모든 후향 / 단점을 생각해 볼 수 있습니까? 개선을 권유 할 수 있습니까?

고맙습니다!

수락 된 답변

구성 대신 MEF 사용

이러한 모든 구성을 취소하고 이러한 공급자를 하드 코딩하고 MEF를 사용하여 응용 프로그램에 포함되어있는 것을 찾아서 사용하면 어떨까요? 그런 다음 다른 DB에 연결할 때 새 공급자를 작성하고 공급자의 어셈블리를 바꿉니 까? MEF는 나머지를 할 것입니다.

재 컴파일없이 생산물을 채우는 새로운 엔티티 추가하기

그러나 주석에 몇 가지 자세한 내용을 추가 했으므로 내가하려는 방식이 몇 가지 변경 사항을 소개하는 것 외에는 갈 길입니다.

  1. 데이터베이스 공급자 검색 기능은 여전히 ​​MEF를 사용하여 구현할 수 있으므로 공급자 어셈블리를 bin 폴더에 놓으면 응용 프로그램이이를 사용하게됩니다. 물론 구성을 통해이 작업을 수행 할 수도 있습니다. 올바른 공급자를 인스턴스화하는 방법을 결정하는 것은 사용자에게 달려 있습니다.

  2. 예제 데이터베이스 스키마에는 사용자가 정의한 구문이있는 것 같습니다. 어쩌면 이미 입증 된 무언가를 사용하고 표준화되고 더 복잡한 정의를 내놓을 수 있습니다.

  3. 사용자 UI (보기 또는 사용자가 사용하는 모든 것)는 실제로는 POCO가 아닌 shcema XML을 사용할 수있는 템플릿입니다. POCO 개체는 데이터를 UI에만 전달 합니다.

  4. 앱에서 반사 기능을 사용하면 기능이 상당히 느려질 수 있습니다. 나는 당신이 더 나은 (= 더 빠른) 접근법을 사용할 것을 제안한다. Mark Gravell의 NuGet에서이 도서관을보십시오 .

디자인 타임 알 수없는 엔터티 생성 및 cosuming

이러한 POCO는 런타임시 XML 스키마에서 생성되므로 데이터 엔티티는 디자인 타임 중에 (컴파일 된 코드의 관점에서) 알 수 없게됩니다. 데이터베이스의 테이블을 직접 조작하는 것처럼 응용 프로그램이 순수하게 데이터베이스 지향적 인 경우가 아니라면 하드 코딩 된 UI로이 엔티티를 어떻게 소비하는지 알 수 없습니까?

UI에서 실제로 동일한 데이터 스키마 UI를 읽고 데이터베이스에서 읽은 POCO 인스턴스를 기반으로 데이터를 채울 수 있습니다. 비즈니스 규칙이나 사용자 인터페이스 프로세스를 추가하지 않고도 응용 프로그램이 순전히 데이터 지향적 인 것이 중요하다면 괜찮습니다.


인기 답변

최종 텍스트를 반환하기 위해 내 솔루션을 제안합니다.

    createPROCEDURE [dbo].[Helper_CreatePocoFromTableName]    
    @tableName varchar(100)
AS
BEGIN
SET NOCOUNT ON;
declare @codeLines table (lineId int, lineText varchar(4000))

insert into @codeLines
Select  rowNr = ROW_NUMBER() over(order by rowNr), PropertyColumn from (
    SELECT 1 as rowNr, 'public class ' + @tableName + ' {' as PropertyColumn
    UNION
    SELECT  rowNr =2 , 'public ' + a1.NewType + ' ' + a1.COLUMN_NAME + ' {get;set;}' as PropertyColumn
    -- ,* comment added so that i get copy pasteable output
     FROM 
    (
        /*using top because i'm putting an order by ordinal_position on it. 
        putting a top on it is the only way for a subquery to be ordered*/
        SELECT TOP 100 PERCENT
        COLUMN_NAME,
        DATA_TYPE,
        IS_NULLABLE,
        CASE 
            WHEN DATA_TYPE = 'varchar' THEN 'string'
            WHEN DATA_TYPE = 'nvarchar' THEN 'string' 
            WHEN DATA_TYPE = 'char' THEN 'string'
            WHEN DATA_TYPE = 'nchar' THEN 'string'
            WHEN DATA_TYPE = 'datetime' AND IS_NULLABLE = 'NO' THEN 'DateTime'
            WHEN DATA_TYPE = 'datetime' AND IS_NULLABLE = 'YES' THEN 'DateTime?'
            WHEN DATA_TYPE = 'smalldatetime' AND IS_NULLABLE = 'NO' THEN 'DateTime'
            WHEN DATA_TYPE = 'datetime2' AND IS_NULLABLE = 'NO' THEN 'DateTime'
            WHEN DATA_TYPE = 'smalldatetime' AND IS_NULLABLE = 'YES' THEN 'DateTime?'
            WHEN DATA_TYPE = 'datetime2' AND IS_NULLABLE = 'YES' THEN 'DateTime?'
            WHEN DATA_TYPE = 'int' AND IS_NULLABLE = 'YES' THEN 'int?'
            WHEN DATA_TYPE = 'int' AND IS_NULLABLE = 'NO' THEN 'int'
            WHEN DATA_TYPE = 'smallint' AND IS_NULLABLE = 'NO' THEN 'Int16'
            WHEN DATA_TYPE = 'smallint' AND IS_NULLABLE = 'YES' THEN 'Int16?'
            WHEN DATA_TYPE = 'decimal' AND IS_NULLABLE = 'NO' THEN 'decimal'
            WHEN DATA_TYPE = 'decimal' AND IS_NULLABLE = 'YES' THEN 'decimal?'
            WHEN DATA_TYPE = 'numeric' AND IS_NULLABLE = 'NO' THEN 'decimal'
            WHEN DATA_TYPE = 'numeric' AND IS_NULLABLE = 'YES' THEN 'decimal?'
            WHEN DATA_TYPE = 'money' AND IS_NULLABLE = 'NO' THEN 'decimal'
            WHEN DATA_TYPE = 'money' AND IS_NULLABLE = 'YES' THEN 'decimal?'
            WHEN DATA_TYPE = 'bigint' AND IS_NULLABLE = 'NO' THEN 'long'
            WHEN DATA_TYPE = 'bigint' AND IS_NULLABLE = 'YES' THEN 'long?'
            WHEN DATA_TYPE = 'tinyint' AND IS_NULLABLE = 'NO' THEN 'byte'
            WHEN DATA_TYPE = 'tinyint' AND IS_NULLABLE = 'YES' THEN 'byte?'
            WHEN DATA_TYPE = 'char' THEN 'string'                       
            WHEN DATA_TYPE = 'timestamp' THEN 'byte[]'
            WHEN DATA_TYPE = 'varbinary' THEN 'byte[]'
            WHEN DATA_TYPE = 'bit' AND IS_NULLABLE = 'NO' THEN 'bool'
            WHEN DATA_TYPE = 'bit' AND IS_NULLABLE = 'YES' THEN 'bool?'
            WHEN DATA_TYPE = 'xml' THEN 'string'
        END AS NewType
        FROM INFORMATION_SCHEMA.COLUMNS 
        WHERE TABLE_NAME = @tableName
        ORDER BY ORDINAL_POSITION
        ) AS a1 
    UNION 
    SELECT 1000 as rowNr,  '} // class ' + @tableName
    ) as t Order By rowNr asc


declare @max int=(select max(lineId) from @codeLines)

-- assembly result 
declare @i int=1
declare @res nvarchar(max)=''

while(@i<=@max)
begin
  set @res = @res +(select lineText +'
  ' from @codeLines l where l.lineId=@i )

  set @i=@i+1
end

select classCode=@res
END


아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.
아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.