dapper PropInfo Setter для унаследованного EntitySet из ссылки на абстрактный класс равен нулю - PullRequest
12 голосов
/ 21 декабря 2011

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

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

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

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

Order

OrderID, Имя, Адрес, RowVersion (внутренний), Отгрузки (EntitySet), OrderDetails (EntitySet), Клиент(EntityRef)

Отгрузка

ShipmentID, OrderID, номер отслеживания

OrderDetails

OrderDetailID, OrderID,Product, QTY, Price

Customer

CustomerID, Name,

Для этого конкретного попадания 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 происходит сбой - переключение на общедоступное, а не на внутреннее решение решило эту проблему - хотя и не желательно.Но тогда это терпит неудачу, когда это пытается создать объекты Отправлений для ЗаказаОпять же, это не проблема, когда Орден является публичным классом.

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

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

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

Ответы [ 2 ]

7 голосов
/ 06 января 2012

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

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?

Мы пошли с «установить его ни на что»

0 голосов
/ 04 января 2012

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

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

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

...