2010-08-27 64 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

如果您首先獲得所有需要選擇的車隊的所有車輛,並且獲得該結果填充車隊對象,那麼我認爲這將是最快的。

現在你確定已經解決了,哪一個最好?