dapper PropInfo抽象クラス参照から継承したEntitySetのSetterがnullです。

.net abstract-class c# dapper reflection

質問

パフォーマンスを向上させるために、いくつかの大まかなクエリでLINQ 2のSQLヒットを置き換えようとしています。そうするには、ASN情報に必要なすべての情報を保持するために必要な大きなオブジェクトを作成するために、さまざまなオブジェクトをまとめて織りなす必要があります。

現在の問題は抽象クラスOrdersであり、このクラスはdiscriminatorプロパティを使用する2つの別々のクラスAutionOrderとMerchantOrderによって実装されています。

私は抽象クラスであるオブジェクトを作成するためにdapperを使うことができないので、代わりにpublicクラスの1つを使用しています。しかし、それはそれは内部に失敗しているオブジェクト構築するために行くときGetSettablePropsそれが正しい発見されDeclaringTypeしかしGetPropertyそれがあるプロパティを探しているとき、このメソッドはnullを返しているinternalまたはあるEntitySet 。私はt.BaseType.GetPropertyp.GetAccessors().First().GetBaseDefinition().DeclaringType.GetProperty(p.Name).GetSetMethod(true)を使ってハックしようとしましたp.GetAccessors().First().GetBaseDefinition().DeclaringType.GetProperty(p.Name).GetSetMethod(true)は成功しませんでした。

ダミーオブジェクト:

注文

OrderID、Name、Address、RowVersion(内部)、Shipments(EntitySet)、OrderDetails(EntitySet)、Customer(EntityRef)

出荷

ShipmentID、OrderID、TrackingNumber

注文詳細

OrderDetailID、OrderID、製品、数量、価格

顧客

顧客ID、名前、

この特定のSQLヒットに対して、私は必要とする1対1の関係マッピングのいくつかを取得しようとしています。

o.OrderIDを(1,2,3)の中でo.CustomerID = c。

これは私がdapperを利用してそれを魔法にするために使用しているものです:

using (var connection = new SqlConnection(_ConnectionString))
{
    connection.Open();
    results = connection.Query<MerchantOrder, MerchantCustomer, MerchantOrder>(sql.ToString(),
        (o, c) => { o.Customer = c; return o; },
        splitOn: "CustomerID");
}

私がOrderをPublicクラスに変更した場合、この問題は解決しますが、これは望ましい副作用ではありません。 RowVersionのpropInfoを設定しようとしたときに失敗しました - 必要ではないが、この問題を内部ではなくパブリックに切り替える。しかし、OrderのShipmentsオブジェクトを作成しようとすると失敗します。これは、Orderがパブリッククラスである場合の問題ではありません。

また、私は、Order to OrderとOrderDetails to Orderのような多対1の関係を引き出し、結果を適切なOrder Objectに正規化するために、別々のクエリを実行しています。 MerchantOrderは、本当の特別なロジックを持たない空のクラスです。ここで差別化しているのは、実際のSQLヒットの前に抽象化されたCustomerIDを見つける方法です。

また、私は12/20/2011の時点で最新版のdapperを使用しています。

私は本当に大嫌いが好きですが、この問題は私の頭が崩れてしまっています - 助けてくれてありがとう!

受け入れられた回答

これはバグで、トランクに修正されました:

public class AbstractInheritance
    {
        public abstract class Order
        {
            internal int Internal { get; set; }
            protected int Protected { get; set; }
            public int Public { get; set; }

            public int ProtectedVal { get { return Protected; } }
        }

        public class ConcreteOrder : Order
        {
            public int Concrete { get; set; }
        }
    }

    // http://stackoverflow.com/q/8593871
    public void TestAbstractInheritance() 
    {
        var order = connection.Query<AbstractInheritance.ConcreteOrder>("select 1 Internal,2 Protected,3 [Public],4 Concrete").First();

        order.Internal.IsEqualTo(1);
        order.ProtectedVal.IsEqualTo(2);
        order.Public.IsEqualTo(3);
        order.Concrete.IsEqualTo(4);

    }

一方の注意点は、設計上、基本クラスにプライベートフィールドやプロパティを設定しないことです。振る舞いは魔法的であり、一貫していない可能性がある

例えば:

class A { private int a {get; set;} }
class B : A { private int a {get; set;} } 
class C: B {} 

// What should "select 1 a" do? Set it on A? Set it on B? Set it on Both? Set it on neither?

私たちは "それを設定しないで"


人気のある回答

あなたのコードを変更することなく(抽象クラ​​スのために)できないと思います。

私は同様の問題を抱え、抽象基底クラスから派生したリポジトリを持つアセンブリにプライベートな新しいオブジェクトを作成しました。

このクラスは抽象クラスではなく 、データを格納するリポジトリクラスにのみ表示されます。このクラスは、実際のテーブルに必要なすべてのメソッドを備えています。



ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow