dapper PropInfo用于从抽象类引用继承的EntitySet的Setter为null

时间:2011-12-21 17:30:34

标签: c# .net reflection abstract-class dapper

我正在尝试用一些精巧的查询替换讨厌的LINQ 2 SQL命中以改善性能。在这样做时,我必须将一堆不同的对象编织在一起,以便创建保存ASN信息所需的所有信息所需的大对象。

我目前遇到的问题是抽象类Orders,这个类是由两个单独的类AutionOrder和MerchantOrder使用discriminator属性实现的。

由于我不能使用dapper来创建一个抽象类的对象,而是使用其中一个公共类。但是当它构建对象时,它在GetSettableProps内失败,它找到了正确的DeclaringType,但GetProperty方法在查找internal属性时返回null。 1}}或者是EntitySet。我试图使用t.BaseType.GetProperty以及p.GetAccessors().First().GetBaseDefinition().DeclaringType.GetProperty(p.Name).GetSetMethod(true)来破解它,但没有成功。

虚拟对象:

  

顺序

     
    

OrderID,名称,地址,RowVersion(内部),货件(EntitySet),OrderDetails(EntitySet),客户(EntityRef)

  
     

装运

     
    

ShipmentID,OrderID,TrackingNumber

  
     

订单明细

     
    

OrderDetailID,OrderID,Product,QTY,Price

  
     

客户

     
    

CustomerID,姓名,

  

对于这个特定的SQL命中,我试图抓住一些我需要的1对1关系映射。

  

SELECT o。* from Orders as o left join customer as c on o.CustomerID = c.CustomerID其中o.OrderID in(1,2,3);

这就是我正在使用的小巧玲珑,让它做到了神奇:

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是公共类时,这一点都不是问题。

此外,我正在进行单独的查询以引入多对一的关系,例如将订单发送到订单和订单的订单详细信息,并将结果规范化为正确的订单对象。 MerchantOrder几乎是一个没有真正特殊逻辑的空类。这里区分不同的是我们最终找到在实际SQL命中之前抽象出来的CustomerID。

此外,我在12/20/2011使用最新版本的dapper。

我真的很喜欢小巧玲珑,但这个问题让我头晕目眩 - 所以感谢你的帮助!

2 个答案:

答案 0 :(得分:7)

这是一个错误,现在已在trunk中修复:

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?

我们选择“不设置它”

答案 1 :(得分:0)

我认为不可能(因为抽象类)没有修改你的代码。

我遇到了类似的问题,最后创建了一个私有的新对象,在那里我拥有了从抽象基类派生的存储库。

此类不是抽象,只对存储数据的存储库类可见,此类具有实际表所需的所有方法。