dapper PropInfo Setter для унаследованного EntitySet из ссылки на абстрактный класс имеет значение null

Я пытаюсь заменить неприятный запрос LINQ 2 SQL некоторыми запросами dapper, чтобы улучшить производительность. При этом я должен сплести кучу разных объектов вместе, чтобы создать большой объект, необходимый для хранения всей информации, необходимой мне для информации ASN.

Текущая проблема, с которой я столкнулся, связана с абстрактным классом Orders, этот класс реализован двумя отдельными классами AutionOrder и MerchantOrder с использованием свойства дискриминатора.

Поскольку я не могу использовать dapper для создания объекта, который является абстрактным классом, я вместо этого использую один из общедоступных классов. однако, когда он идет на построение объекта, он терпит неудачу внутри GetSettableProps, он находит правильный DeclaringType, но метод GetProperty возвращает null, когда ищет свойство, равное internal или EntitySet. Я безуспешно пытался обойти это с помощью t.BaseType.GetProperty, а также p.GetAccessors().First().GetBaseDefinition().DeclaringType.GetProperty(p.Name).GetSetMethod(true).

фиктивные объекты:

порядок

OrderID, имя, адрес, RowVersion (внутренний), отгрузки (EntitySet), OrderDetails (EntitySet), Customer (EntityRef)

Отгрузка

ShipmentID, OrderID, TrackingNumber

Информация для заказа

OrderDetailID, OrderID, Product, QTY, Price

Покупатель

CustomerID, имя,

Для этого конкретного запроса SQL я пытаюсь получить некоторые нужные мне сопоставления отношений 1 к 1.

ВЫБЕРИТЕ o. * Из заказов как o осталось, присоединитесь к клиентам как c o.CustomerID = c.CustomerID, где o.OrderID в (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 на публичный класс, эта проблема исчезнет, ​​но это нежелательный побочный эффект. Ошибка при попытке установить propInfo для RowVersion - переключение на общедоступное вместо внутреннего решило эту проблему, хотя и нежелательно. Но затем он терпит неудачу, когда пытается создать объекты отгрузки для заказа. Опять же, все это не является проблемой, когда Order является общедоступным классом.

Кроме того, я делаю отдельные запросы, чтобы вывести отношения «многие к одному», такие как «Отгрузки к заказам» и «Детали заказа» к заказам, и нормализовать результаты в соответствующий объект заказа. MerchantOrder - это практически пустой класс без особой логики. Отличительная особенность здесь заключается в том, как мы в конечном итоге находим CustomerID, который в любом случае абстрагируется до фактического обращения к SQL.

Также я использую последнюю версию dapper по состоянию на 20.12.2011.

Мне очень нравится dapper, но от этой проблемы у меня голова взрывается - спасибо за помощь!


person John    schedule 21.12.2011    source источник
comment
вы можете добавить неудачный тест, чтобы я мог это исправить? просто отправьте патч с ним   -  person Sam Saffron    schedule 29.12.2011
comment
Я добавил тест на сбой @ code.google.com/r/johnzaborow-fail- test У меня было много проблем с автоматическим продвижением моих изменений, поэтому я делал это один за другим. дайте мне знать, если что-то нужно изменить. Благодарность!   -  person John    schedule 05.01.2012


Ответы (2)


Это была ошибка, которая теперь исправлена ​​в багажнике:

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

    }

С одной стороны, мы специально не устанавливаем частные поля или свойства в базовых классах. Поведение может быть волшебным и непостоянным.

Eg:

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?

Мы пошли с "не включайте ни то, ни другое"

person Sam Saffron    schedule 05.01.2012
comment
Большое спасибо за исправление! Это заставило меня некоторое время чесать затылок! Лучший подарок на день рождения, который я получил в этом году! - person John; 09.01.2012

Я думаю, что это невозможно (из-за абстрактного класса) без изменения вашего кода.

У меня была аналогичная проблема, и в итоге я создал новый объект, частный для сборки, где у меня есть мои репозитории, производные от абстрактного базового класса.

Этот класс не является абстрактным и виден только классу репозитория, в котором хранятся данные, у этого класса были все необходимые методы для реальной таблицы.

person nahog    schedule 03.01.2012