Dapper PropInfo Setter für das geerbte EntitySet von der abstrakten Klassenreferenz ist null

.net abstract-class c# dapper reflection

Frage

Ich versuche, einen bösen LINQ 2 SQL-Treffer durch einige bessere Abfragen zu ersetzen, um die Leistung zu verbessern. Dabei muss ich eine Menge verschiedener Objekte miteinander verweben, um ein großes Objekt zu erstellen, das alle Informationen enthält, die ich für ASN-Informationen benötige.

Das aktuelle Problem, das ich habe, ist mit einer abstrakten Klasse Orders, diese Klasse wird durch zwei getrennte Klassen AutionOrder und MerchantOrder unter Verwendung einer Diskriminatoreigenschaft implementiert.

Da ich Dapper nicht verwenden kann, um ein Objekt zu erstellen, das eine abstrakte Klasse ist, verwende ich stattdessen eine der öffentlichen Klassen. Wenn jedoch das Objekt GetSettableProps wird, das in GetSettableProps , wird der richtige DeclaringType aber die GetProperty Methode gibt null zurück, wenn nach einer Eigenschaft gesucht wird, die internal oder EntitySet . Ich habe versucht, es mit t.BaseType.GetProperty sowie p.GetAccessors().First().GetBaseDefinition().DeclaringType.GetProperty(p.Name).GetSetMethod(true) zu hacken p.GetAccessors().First().GetBaseDefinition().DeclaringType.GetProperty(p.Name).GetSetMethod(true) ohne Erfolg.

Dummy-Objekte:

Auftrag

OrderID, Name, Adresse, RowVersion (intern), Sendungen (EntitySet), OrderDetails (EntitySet), Kunde (EntityRef)

Sendung

Sendungs-ID, Bestell-ID, Sendungsnummer

Bestelldetails

OrderDetailID, OrderID, Produkt, Menge, Preis

Kunde

Kundennummer, Name,

Für diesen speziellen SQL-Treffer versuche ich einige der 1: 1-Beziehungszuordnungen zu finden, die ich brauche.

WÄHLEN Sie o. * Aus Bestellungen als o links Kunden als c auf o.CustomerID = c.CustomerID wo o.OrderID in (1,2,3);

Das ist es, was ich benutze, um adrett zu wirken und es magisch zu machen:

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");
}

Wenn ich Order ändere, um eine öffentliche Klasse zu sein, geht dieses Problem jedoch weg, aber dies ist kein gewünschter Nebeneffekt. Es schlägt fehl, wenn versucht wird, die propInfo für RowVersion zu setzen - das Umschalten auf public statt intern löste dieses Problem - obwohl nicht gewünscht. Aber es schlägt fehl, wenn versucht wird, die Sendungsobjekte für Order zu erstellen. Auch dies ist kein Problem, wenn Order eine öffentliche Klasse ist.

Ich mache auch separate Abfragen, um viele Beziehungen wie Aufträge zu Bestellungen und OrderDetails zu Bestellungen zu ziehen und die Ergebnisse in ein ordentliches Order-Objekt zu normalisieren. MerchantOrder ist eine leere Klasse ohne besondere Logik. Die Unterscheidung unterscheidet sich hier nur darin, wie wir die CustomerID finden, die sowieso vor dem eigentlichen SQL-Treffer abstrahiert wurde.

Auch ich benutze die neueste Version von dapper per 20.12.2011.

Ich mag wirklich adrett, aber dieses Problem macht meinen Kopf asplode - also danke für die Hilfe!

Akzeptierte Antwort

Dies war ein Fehler, der jetzt im Stamm behoben ist:

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);

    }

Eine Randnotiz ist, dass wir per Definition keine privaten Felder oder Eigenschaften in den Basisklassen festlegen. Das Verhalten kann magisch und nicht konsistent sein.

Z.B:

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?

Wir gingen mit "auf keinen der beiden"


Beliebte Antwort

Ich denke, ist nicht möglich (wegen der abstrakten Klasse), ohne Ihren Code zu ändern.

Ich hatte ein ähnliches Problem und habe schließlich ein neues Objekt erstellt, das für die Assembly privat ist, wo ich meine Repositories habe, die von der abstrakten Basisklasse abgeleitet sind.

Diese Klasse ist nicht abstrakt und nur für die Repository-Klasse sichtbar, die die Daten speichert. Diese Klasse verfügt über alle erforderlichen Methoden für die tatsächliche Tabelle.



Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum
Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum