14

最近、Dapper を調べ始めました。私はそれをテストしていて、基本的な CRUD を実行できました。基本とは、次の構造を持つクラスで作業することです。

public class Product {
    public int Id {get;set;}
    public string Name {get;set;}
}

今、挿入と更新を簡単にするものを探していて、Dapper.Rainbow を見つけました。私はそれをチェックアウトし、それを使用して上記のようにオブジェクトを取得および挿入できました。私の問題はProduct、ナビゲーション プロパティがある場合、そのフィールドに挿入できないことです。だから私はこれを持っている場合:

public class Product {
    public int Id {get;set;}
    public string Name {get;set;}
    public ProductCategory Category {get;set;}
}

私はこれを行うことができません:

// connection is a valid and opened connection            
 var db = TestDatabase.Init(connection , 300);
 var newId = db.Products.Insert(newProduct);

この理由により:

The member Category of type ProductCategory  cannot be used as a parameter value

Categorytype int(データベース内の同じデータ型)に置き換えると、問題を解決できます。ただし、そうすると、(カテゴリ)IDだけでなく、カテゴリ情報を使用して製品を照会できなくなります。

生の Dapper に頼らずに、ナビゲーション プロパティを持つクラスを使用して挿入と更新を行うにはどうすればよいでしょうか? Category次のことを実行して、挿入または更新時に無視するように Dapper.Rainbow に指示できることを望んでいました。

public class Product {
    public int Id {get;set;}
    public string Name {get;set;}
    public ProductCategory Category {get;set;}
    public int CategoryId {get;set;} // this will be the same field name in the database
}

このシナリオは、NHibernate で可能であり、プロキシ オブジェクトを取得してCategory割り当ててProduct保存することができ、マッピングは完全に機能します。しかし、私は Dapper を使いたいと思っています。そのため、このようなことがどのように行われるかを調査し、学びたいと思っています。

4

2 に答える 2

26

Dapper.Rainbow ではありません

これはDapper.Rainbow現在の形式では不可能ですが、github のプル リクエストにより可能になりました。

誰も使用を提案していないことに驚いていますDapper.Contrib。機能がレインボーにあるかどうかを尋ねたことは知っています。しかし、私は誰もこの声明に気付かないとは思っていませんでした (特に太字のテキスト):

今、挿入と更新を簡単にするものを探していて、 Dapper.Rainbow を見つけました。私はそれをチェックアウトし、それを使用して上記のようにオブジェクトを取得および挿入できました。私の 問題は、 Product にナビゲーション プロパティがある場合、そのフィールドに挿入できないことです

...そして、Dapper ライブラリに既にある代替案を提案します。私は自分の質問をより明確にし、github にある Dapper ライブラリ全体のどこかに解決策が存在するかどうかを明示的に尋ねるべきだったと思います。そのため、ライブラリをさらに掘り下げた後、私の問題に対するサポートがあることがわかりました。

Dapper.Contrib へのパス

すべてが私のプロジェクトでうまく機能しており、Rainbowさらに必要になるまで. 多くのフィールドを含むテーブルをいくつか取得しました。オブジェクトに Rainbow をフィードするだけでは、すべてのフィールドで更新が行われますが、それはすべて良いことではありません。しかし、だからといってすぐに船から飛び降りて NH に戻るわけではありません。だから私は自分自身を実装する前にchange tracking、特に誰かがすでに良い仕事をしている場合、車輪を再発明したくありませ. そのスレッドは、Rainbow変更追跡をサポートしていないという私の知識を確認しましたが、別の獣があり、それはDapper.Contrib. それで、私はそれを試し始めました。

そしてまた会う

タイプ ProductCategory のメンバ カテゴリはパラメータ値として使用できません

と同じ問題が発生しましたRainbowContribはナビゲーション プロパティをサポートしていません!? で時間を無駄にしていると感じ始めておりDapper、それが提供するパフォーマンスは、私が非常に求めているものですが、希望的観測にすぎません. それまで...

WriteAttribute が助けになりました...

このクラスは、プロジェクトSqlMapperExtensions.csに含まれるファイルに存在します。Dapper.Contribこのクラスに関するドキュメントは見つかりませんでした。また、簡単に見つけて私に叫んで言うことができるコメントもありませんhey I'm the one you're looking for。上記のようにレインボーを脇に置いたときに、これに出くわしました。

このクラスの使用法は、私が で行ったものと同じです。これはIgnorePropertyAttribute、クラスのプロパティを装飾できる属性です。sql作成するに含めたくないプロパティは、この属性でデコレートする必要がありDapperます。したがって、私の例では、Dapper にCategoryフィールドを除外するように指示するには、次のようにする必要がありました。

public class Product {
    public int Id {get;set;}

    public string Name {get;set;}

    [Write(false)] // tell Dapper to exclude this field from the sql
    public ProductCategory Category {get;set;}

    public int CategoryId {get;set;}
}

私はほとんどそこにいます

Contrib私が行く理由は機能性のためであることを忘れないでくださいchange tracking. 上記の同じリンクであるこの SO スレッドは、変更追跡を有効にするには、クラスのインターフェイスが必要であり、それを で使用する必要があると述べていますContrib。したがって、私の例のクラスでは、次のものが必要です。

public interface IProduct {
    int Id {get;set;}
    string Name {get;set;}
    ProductCategory Category {get;set;}
    int Category {get;set;}
}

// and implement it on my Product class
public class Product : IProduct {
    public int Id {get;set;}

    public string Name {get;set;}

    [Write(false)]
    public ProductCategory Category {get;set;}

    int Category {get;set;}
}

私はそれがほとんどだと思いました!まったく気にしないのに、なぜCategoryインターフェイスで定義する必要があるのか​​ 疑問に思われるかもしれません。Dapper実際、それは問題を引き起こすだけであり、私が解決する問題です。

Category私の特定のシナリオでは、オブジェクトの変更追跡を維持しながらフィールドで作業する必要がある場合がありProductます。追跡機能を維持するには、get 呼び出しに次のようなインターフェイス タイプを指定する必要があります。

var product = connection.Get<IProduct>(id);

その呼び出しでは、インターフェイスでフィールドを定義しないと、フィールドにアクセスできません。Categoryしかし、インターフェースで定義すると、おなじみのエラーが発生します

タイプ {type} のメンバー {member} はパラメーター値として使用できません。

本当にまた?やめてください。

評決

これは、クラスに対して行ったのと同じようにインターフェイス メンバーを装飾することで簡単に解決できるため、心配する必要はありません。したがって、すべてを機能させるための最終的な構成は次のようになります。

public interface IProduct {
    // I will not discuss here what this attribute does
    // as this is documented already in the github source.
    // Just take note that this is needed,
    // both here and in the implementing class.
    [Key]
    int Id {get;set;}

    string Name {get;set;}

    [Write(false)]
    ProductCategory Category {get;set;}

    int Category {get;set;}
}

// and implement it on my Product class
public class Product : IProduct {
    [Key]        
    public int Id {get;set;}

    public string Name {get;set;}

    [Write(false)]
    public ProductCategory Category {get;set;}

    int Category {get;set;}
}

Contrib機能を備えたものを使用したい場合は、このアプローチを使用できますchange tracking。私とRainbow同じように、ナビゲーション プロパティを使用して問題を抱えている場合は、私のプル リクエストを試してみてください。のみで動作する と同じようWriteAttributeに動作しRainbowます。

クラスを属性で装飾するのが好きでない場合は、どちらの拡張プロジェクトも適していません。ある種の流暢な構成を可能にする別の拡張プロジェクトがあることは知っていますが、それは github にあるライブラリとは一致しませ(コア部分として含まれていません) 。Dapper私の好みは、コア ライブラリのみを操作することであり、ライブラリ全体を調査して、既存のものがあるかどうか、またはニーズを満たすために改善できるかどうかを確認するようになりました。そして、それが私がここで行って説明したことRainbowですContrib

この貢献、私が追加した非常に単純なクラス、私が示した構成のヒント、およびそれらを導くシナリオが、将来 Dapper を使用したいと考えている誰かを助け、それが私と同様のセットアップを持つことを願っています。また、この回答により、Dapper でできることとできないことについて、開発者がより多くのことを学ぶことができます。と呼ばれるこの優れたツールDapper は、より良いwikiに値するものであり、SOのこの回答/記事が少しでも役立つことを願っています.


**そして、私がここに書いたことがすでにどこかに書かれていて、回答を待っている2週間の時間で見つけられなかった場合は、誰かが私をリンクしてくれることを嬉しく思います. 2 週間経ちましたが、私の質問を調べた 29 人がリンクや解決策を提案していないので、ここで共有した情報は Dapper にとって新しいものだと思いました :)

注:質問のタイトルを変更して、他の人が問題に対するこの潜在的な解決策を確認できるようにしました。新しいタイトルは、私が Dapper について得た新しい知識に基づいています。

于 2013-04-12T06:31:23.270 に答える