12

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

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

dapperを使用して抽象クラスであるオブジェクトを作成することはできないため、代わりにパブリッククラスの1つを使用しています。ただし、オブジェクトをビルドしようとすると、オブジェクトの内部で失敗しGetSettableProps、適切なものが見つかりますDeclaringTypeが、メソッドは、またはでGetPropertyあるプロパティを検索するときにnullを返します。私はそれを使ってハックしようとしましたが、成功しませんでした。internalEntitySett.BaseType.GetPropertyp.GetAccessors().First().GetBaseDefinition().DeclaringType.GetProperty(p.Name).GetSetMethod(true)

ダミーオブジェクト:

注文

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

発送

ShipmentID、OrderID、TrackingNumber

注文詳細

OrderDetailID、OrderID、Product、QTY、Price

お客様

CustomerID、名前、

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

SELECTo。*fromOrders as o left join Customers as c on o.CustomerID = c.CustomerID where o.OrderID in(1,2,3);

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

また、ShipmentstoOrdersやOrderDetailstoOrdersなどの多対1の関係を取得し、結果を適切なOrder Objectに正規化するために、個別のクエリを実行しています。MerchantOrderはほとんど空のクラスであり、実際の特別なロジックはありません。ここでの識別の違いは、実際のSQLヒットの前に抽象化されたCustomerIDを最終的に見つける方法です。

また、2011年12月20日現在の最新バージョンのdapperを使用しています。

私はdapperが本当に好きですが、この問題は私の頭を混乱させています-助けてくれてありがとう!

4

2 に答える 2

7

これはバグで、現在はトランクで修正されています:

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?

「どちらにも設定しない」で行きました

于 2012-01-05T23:00:00.183 に答える
0

コードを変更しないと(抽象クラ​​スのため)不可能だと思います。

同様の問題があり、抽象基本クラスから派生したリポジトリがあるアセンブリにプライベートな新しいオブジェクトを作成することになりました。

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

于 2012-01-03T22:06:41.917 に答える