2010-08-27 73 views
1

我可以使用一些帮助来确定从SQL数据库中检索父子对象的最佳(最高性能/易维护)策略。父子表的SQL策略

我继承了这段代码,而且我已经有了相对较短的截止日期,我希望尽可能少做基础性更改。我有足够的时间在下一个螺旋上实现nhibernate或其他ORM,我现在不能这样做。我以最少的修改时间在最短的时间内寻找最好的事情。

扭曲的是,有不同的儿童类型(实现一个普通的儿童界面)。

例如,
家长:VehicleFleet(包含车队名称,经理姓名,车辆列表)
儿童:IVehicle(包括制造商,型号,位置等)

但是,可能有多个车辆类型 - 例如汽车,厢式车,摩托车 - 各具有不同的属性/列。有一个独立的汽车,面包车和摩托车。可能有也可能没有VehicleBase表,其中包含适用于任何车辆的列。

返回多个VehicleFleet对象的最佳策略是什么,每个对象都有相关的Vehicle子对象?

这里有一对夫妇的战略我已经试过(伪代码提交) -

假设:
所有的getXXXX功能使用DataReader场景

方法1落后:简单&慢 - 这是做的最糟糕的方式,原因很明显

IEnumerable<Fleet> GetFleetsAndVehicles() { 
foreach (var fleet in myFleetDao.GetAllFleets()) { 
    foreach (var vehicleTypeDao in myVehicleTypeDaos) 
    fleet.Vehicles.Add (vehicleTypeDao.GetVehicles (fleet.Id); 
    yield return fleet; 
} 
yield break; 
} 

方法2:预取儿童

IEnumerable<Fleet> GetFleetsAndVehicles() { 
var allVehicles = (from vtd in myVehicleTypeDaos 
    from v in vtd.GetAllVehicles() 
    select v).ToLookup (v => v.FleetId); 

foreach (var fleet in myFleetDao.GetAllFleets()) 
{ 
    fleet.Vehicles = allVehicles[fleet.Id].ToList(); 
    yield return fleet; 
} 
yield break; 
} 

方法3:预取儿童,儿童附加异步地

IEnumerable<Fleet> GetFleetsAndVehicles() { 
foreach (var fleet in new AsyncGetter.GetFleetsAndVehicles()) 
    yield return fleet; 
yield break; 
} 

class AsyncGetter 
{ 
// left out instance variables, Auto/Manual Reset Events, locking, etc. for brevity 
IEnumerable<Fleet> GetFleetsAndVehicles() 
{ 
    StartAsyncStuff(); 

    while (myUnconsumedFleets.Count > 0) 
    { 
    yield return myUnconsumedFleets.Remove (0); 
    WaitUntilMoreFleetsAreAdded(); 
    } 
    yield break; 
} 

void StartAsyncStuff() 
{ 
    myAllVehicles = <same as method 2> 

    foreach (var fleet in myFleetDao.GetAllFleets()) 
    { 
    AttachVehiclesAsync (fleet); 
    } 
} 

void AttachVehiclesAsync (Fleet f) 
{ 
    // assume using ThreadPool.QueueUserWorkItem right now 
    WaitForAllVehiclesToLoad(); 
    f.Vehicles = myAllVehicles[f.Id].ToList(); 
    myUnconsumedFleets.Add (f); 
} 
} 

方法4:交错的父/子查询

IEnumerable<Fleet> GetFleetsAndVehicles() { 
var allVehicles = from vtd in myVehicleTypeDaos 
    from v in vtd.GetAllVehicles() 
    orderby v.FleetId 
    select v; 
var allVehiclesEnumerator = allVehicles.GetEnumerator(); 

foreach (var fleet in myFleetDao.GetAllFleets()) 
{ 
    fleet.Vehicles = GetAllChildVehiclesAndMaintainEnumeratorPosition (allVehiclesEnumerator, fleet); 
    yield return fleet; 
} 
} 

到目前为止,使用一些测试数据,我看到那个方法3是最高性能的(快于下一个最佳速度27%),而方法1是最差的(比方法1慢4倍)。

所以,如果你有建议,我很乐意听到他们!

+0

如果您可以自由选择单个表继承模型,而不是在LINQ2SQL中内置支持,请参阅http://msdn.microsoft.com/en-us/library/bb399352.aspx和http:// msdn。 microsoft.com/en-us/library/bb386919.aspx – 2010-08-28 07:14:01

回答

0

由于没有提供有用的答案来解决手头问题,所以我需要说:I thought we had left the 'DIY data access layers' behind these days。当然,可能还有一些用例确实需要自定义数据读取器。尽管如此,将继承层次从数据库映射到对象模型通常不是其中之一。

有大量的ORM可用于解决这个问题。它被称为“Table per Type继承映射”。任何体面的ORM都支持这一点,并允许您热切地获取父母/子女关系。

如果表现真的是一个问题(是吗?),那么通过切换到“单表继承”策略(一个表中的所有类型,带有鉴别器列),您可能会获得最多的收益。

实体框架和NHibernate都支持单表和每表类型。 Linq 2 SQL(好吧,也许不是完整的ORM)只支持单表继承;正如@Albin Sunnanbo所说,如果您可以更改数据库模式,那么它可能是一个选项。还有很多其他的ORM值得研究。

在那里,它离开我的胸部;-),希望它有帮助。

+0

这是一个完全可以接受的答案......但不是现在。我继承了一个项目,而且我已经有了相对较短的截止日期,我希望尽可能少做基础性的改变。我有足够的时间在下一个螺旋上实现nhibernate,我现在不能这样做。 我正在寻找最短的时间做最好的事情,以最少的修改。 – PhilChuang 2010-08-29 06:31:23

0

如果您首先获得所有需要选择的车队的所有车辆,并且获得该结果填充车队对象,那么我认为这将是最快的。

现在你确定已经解决了,哪一个最好?