4

テーブルから多数の「マスター」行を選択し、結果ごとに別のテーブルから多数の詳細行を返す必要があります。複数のクエリを使用せずにこれを達成する良い方法は何ですか (マスター行用に 1 つと、詳細行を取得するための結果ごとに 1 つ)。

たとえば、次のようなデータベース構造を使用します。

MasterTable:
    - MasterId BIGINT
    - Name NVARCHAR(100)

DetailTable:
    - DetailId BIGINT
    - MasterId BIGINT
    - Amount MONEY

data以下のオブジェクトを最も効率的に設定するにはどうすればよいですか?

IList<MasterDetail> data;

public class Master
{
    private readonly List<Detail> _details = new List<Detail>();

    public long MasterId
    {
        get; set;
    }

    public string Name
    {
        get; set;
    }

    public IList<Detail> Details
    {
        get
        {
            return _details;
        }
    }
}

public class Detail
{
    public long DetailId
    {
        get; set;
    }

    public decimal Amount
    {
        get; set;
    }
}
4

6 に答える 6

3

次のような単一のクエリで実行できます。

select   MasterTable.MasterId,
         MasterTable.Name,
         DetailTable.DetailId,
         DetailTable.Amount
from     MasterTable
         inner join
         DetailTable
         on MasterTable.MasterId = DetailTable.MasterId
order by MasterTable.MasterId

次に、疑似コードで

foreach(row in result)
{
   if (row.MasterId != currentMaster.MasterId)
   {
       list.Add(currentMaster);
       currentMaster = new Master { MasterId = row.MasterId, Name = row.Name };
   }
   currentMaster.Details.Add(new Detail { DetailId = row.DetailId, Amount = row.Amount});
}
list.Add(currentMaster);

それを打ち破るいくつかのエッジがありますが、それはあなたに一般的なアイデアを与えるはずです.

于 2008-11-25T11:41:06.847 に答える
3

通常、私は 2 つのグリッド アプローチを使用しますが、FOR XML も参照することをお勧めします。(SQL Server 2005 以降では) 親/子データを xml として整形し、それをロードするのはかなり簡単です。そこの。

SELECT parent.*,
       (SELECT * FROM child
       WHERE child.parentid = parent.id FOR XML PATH('child'), TYPE)
FROM parent
FOR XML PATH('parent')

また、LINQ-to-SQL はこのタイプのモデルをサポートしていますが、必要なデータを事前に指定する必要があります。DataLoadOptions.LoadWith経由:

// sample from MSDN
Northwnd db = new Northwnd(@"c:\northwnd.mdf");
DataLoadOptions dlo = new DataLoadOptions();
dlo.LoadWith<Customer>(c => c.Orders);
db.LoadOptions = dlo;

var londonCustomers =
    from cust in db.Customers
    where cust.City == "London"
    select cust;

foreach (var custObj in londonCustomers)
{
    Console.WriteLine(custObj.CustomerID);
}

を使用しない場合LoadWith、n+1 個のクエリ (マスター行ごとに 1 つのマスター リストと 1 つの子リスト) が取得されます。

于 2008-11-25T11:36:15.903 に答える
0

これは、検討できる代替案です。開発者あたり 150 ドルかかりますが、時は金なりです...

Entity Spacesと呼ばれるオブジェクト永続化レイヤーを使用して、コードを生成し、スキーマが変更されるたびに再生成することができます。オブジェクトへのデータの移入は透過的です。上で説明したオブジェクトを使用すると、次のようになります (VB で失礼しますが、C# でも機能します)。

Dim master as New BusinessObjects.Master
master.LoadByPrimaryKey(43)
Console.PrintLine(master.Name)
For Each detail as BusinessObjects.Detail in master.DetailCollectionByMasterId
   Console.PrintLine(detail.Amount)
   detail.Amount *= 1.15
End For
With master.DetailCollectionByMasterId.AddNew
   .Amount = 13
End With
master.Save()
于 2008-11-29T01:18:17.260 に答える
0

マスターから <列> を選択

select < columns > from master M join Child C on M.Id = C.MasterID

于 2008-11-25T11:11:58.170 に答える
0

2 つのクエリと、各結果セットに対する 1 つのパスでそれを行うことができます。

MasterId で並べ替えられたすべてのマスターを照会してから、同じく MasterId で並べ替えられたすべての詳細を照会します。次に、2 つの入れ子になったループで、マスター データを反復し、メイン ループの行ごとに新しいマスター オブジェクトを作成し、現在のマスター オブジェクトと同じ MasterId を持つ詳細を反復し、入れ子になったループでその _details コレクションを設定します。

于 2008-11-25T11:16:01.297 に答える
0

データセットのサイズに応じて、2 つのクエリ (すべてのマスターに対して 1 つとすべてのネストされたデータに対して 1 つ) を使用してすべてのデータをメモリ内のアプリケーションにプルし、それを使用してオブジェクトごとにサブリストをプログラムで作成し、何かを与えることができます。お気に入り:

List<Master> allMasters = GetAllMasters();
List<Detail> allDetail = getAllDetail();

foreach (Master m in allMasters)
    m.Details.Add(allDetail.FindAll(delegate (Detail d) { return d.MasterId==m.MasterId });

このアプローチでは、基本的にメモリフットプリントを速度と交換しています。これを簡単に調整して、関心のあるマスター アイテムGetAllMastersGetAllDetailディテール アイテムのみを返すことができます。また、これを有効にするには、MasterId をディテール クラスに追加する必要があることに注意してください。

于 2008-11-25T11:17:36.863 に答える