Dapper用SQLクエリジェネレータ

c# dapper orm sql

質問

こんにちは、新しいプロジェクトで使用する最高のパフォーマンスを持つORMを探していました。私の最終的な選択はDapperになった。また、Dapperに渡すSQLクエリをハードコーディングできないようにするために、少なくとも以下の機能を含むようにアプリケーションを用意する必要があります

  1. データベースに依存しない
  2. 実行時エンティティ定義

私はDapper用のSQLジェネレータを書くことを考えましたが、私が従うアプローチがベストであるかどうかはわかりません:

  1. メソッドシグネチャを持つインタフェースを宣言します。実装は、使用するデータベースシステム(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は合法ですか? はい、理由を学ぶ