12

我正在尝试用一些简洁的查询替换讨厌的 LINQ 2 SQL 命中以提高性能。这样做时,我必须将一堆不同的对象编织在一起,以创建一个大对象,以保存我需要的所有 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(内部)、Shipments(EntitySet)、OrderDetails(EntitySet)、Customer(EntityRef)

运输

ShipmentID、OrderID、TrackingNumber

订单详细信息

OrderDetailID、OrderID、产品、数量、价格

顾客

客户 ID、姓名、

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

SELECT o.* from Orders 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 时失败 - 将其切换为 public 而不是 internal 解决了这个问题 - 尽管不需要。但是当它试图为 Order 创建 Shipments 对象时它会失败。同样,当 Order 是公共类时,这些都不是问题。

此外,我正在执行单独的查询以引入多对一关系,例如 Shipments 到 Orders 和 OrderDetails 到 Orders 并将结果规范化为适当的 Order 对象。MerchantOrder 几乎是一个没有真正特殊逻辑的空类。这里的区别在于我们最终如何找到在实际 SQL 命中之前抽象出来的 CustomerID。

此外,我正在使用截至 2011 年 12 月 20 日的最新版本的 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 回答