我可以使用一些帮助来确定从SQL db中检索父子对象的最佳(最高性能/易于维护)策略。
我继承了这段代码,而且我的截止日期相对较短,我希望尽可能少地进行基础更改。我将有足够的时间用下一个螺旋来实现nhibernate或其他ORM,我现在不能这样做。我正在寻找最好的事情,在最短的时间内完成最少的修改。
扭曲是有不同的子类型(实现一个共同的子接口)。
例如,
父级:VehicleFleet(包含车队名称,经理名称,车辆清单)
儿童:IVehicle(包含品牌,型号,位置等)
然而,可能存在多种类型的IVehicle - 例如Car,Van,Motorcycle - 每种都具有不同的属性/列。汽车,厢式车和摩托车有一个单独的桌子。可能有也可能没有VehicleBase表,其中包含适用于任何IVehicle的列。
返回多个VehicleFleet对象的最佳策略是什么,每个对象都有相关的车辆孩子?
这是我尝试过的一些策略(以伪代码表示) -
假设:
所有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 :(得分:0)
由于没有为手头的问题提供有用的答案而被贬低的风险,我仍然需要说:I thought we had left the 'DIY data access layers' behind these days。当然,可能仍有一些用例,你真的需要做一些自定义数据阅读器魔术。将继承层次结构从数据库映射到对象模型通常不是其中之一。
有很多ORM可以解决这个问题。它被称为“每种类型的表继承映射”。任何体面的ORM都支持这一点,并允许您急切地获取父/子关系。
如果性能真的是一个问题(是吗?),那么你可能会通过切换到“单表继承”策略(一个表中的所有类型,带有鉴别器列)来获得最大收益。 / p>
Entity Framework和NHibernate都支持开箱即用的单表和每表类型。 Linq 2 SQL(好的,可能不是完整的ORM)只支持单表继承;正如@Albin Sunnanbo所说,如果你可以改变数据库模式,它可能是一个选项。还有很多其他的ORM值得调查。
在那里,它不在我的胸前;-),希望它有所帮助。
答案 1 :(得分:0)
我认为如果您首先获得所有需要选择的车队的所有车辆,并且在获得该结果时填充车队对象,那么它将是最快的。
现在你肯定已经解决了,哪一个是最好的?