1

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

  1. データベースに依存しない
  2. ランタイムエンティティの定義

Dapper用のSQLジェネレーターを作成することを考えましたが、私が従うアプローチが最適かどうかはわかりません。

  1. メソッドシグネチャを使用してインターフェイスを宣言します。実装は、使用するデータベースシステム(SQL Server / MySQL / PostgreSql / DB2 / Oracle /など)に対応しています。
  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. (反射を使用して)現在のエンティティのプロパティをループし、プロパティが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)*/
    

このアプローチの欠点/欠点について考えてみてください。改善点をお勧めしますか?

ありがとうございました!

4

2 に答える 2

1

構成の代わりにMEFを使用する

これらの構成をすべて却下し、これらのプロバイダーをハードコーディングし、MEFを使用して、アプリケーションに含まれているものを検出し、そのプロバイダーを使用するとしたらどうでしょうか。次に、別のDBに接続するときに、新しいプロバイダーを作成して、プロバイダーのアセンブリを置き換えますか?その後、MEFが残りを行います。

再コンパイルせずに生産を行う新しいエンティティを追加する

しかし、コメントにさらにいくつかの詳細を追加したので、私がいくつかの変更を紹介することを除いて、あなたがやろうとしている方法は進むべき道であると言いたいです:

  1. データベースプロバイダーの検出可能性は引き続きMEFを使用して実装できるため、プロバイダーアセンブリをbinフォルダーにドロップするだけで、アプリはそれを使用します。もちろん、これは構成によっても実行できます。正しいプロバイダーをインスタンス化する方法を決定するのはあなた次第です。

  2. サンプルのデータベーススキーマには、自分で定義した構文があるようです。おそらく、すでに証明されており、標準化された、おそらくより複雑な定義を可能にするものを使用することもできます。

  3. UI(ビューまたは使用するもの)は、実際には、POCOではなくスキーマXMLを使用できるテンプレートになります。POCOオブジェクトは、UIにのみデータを配信します。

  4. アプリでリフレクションを広範囲に使用するため、リフレクションが大幅に遅くなる可能性があります。より良い(=より速い)アプローチを使用することをお勧めします。MarkGravellによるNuGetでこのライブラリを見てください。

設計時の未知のエンティティの生成と消費

これらのPOCOは実行時にXMLスキーマから生成されるため、データエンティティは(コンパイルされたコードの観点から)設計時に不明になります。アプリケーションが純粋にデータベース指向でない限り(データベース内のテーブルを直接操作する場合のように)、ハードコードされたUIでこれらのエンティティをどのように使用するかわかりませんか?

おっしゃるように、UIは実際に同じデータスキーマUIを読み取り、データベースから読み取られたPOCOインスタンスに基づいてデータを取り込むことができます。アプリケーションが追加のビジネスルールやユーザーインターフェイスプロセスなしで純粋にデータ指向であることが理にかなっている限り、それはすべて問題ありません。

于 2012-10-22T07:21:41.787 に答える
0

最終的なテキストを返すために、私は自分の解決策を提案します。

    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
于 2015-01-30T13:13:24.553 に答える