1

Org インスタンスの階層を有効にするために、( Consumer を指す) とプロパティOrgを持つclassがあります。プロパティを持つclass もあります。という名前の Org インスタンスが与えられた場合、その組織のすべての Customer インスタンスを取得するにはどうすればよいですか? つまり、LINQ を使用する前は、ルートとして Org ツリーを「手動で」トラバーサルしていました。しかし、もっと単純なものが存在すると確信しています。ParentIdOrgsCustomerOrgIdOwnerOwner

例: 'Film' という名前のルート レベルの組織、ID '1' と、'Horror' というサブ組織、ParentId '1'、ID 23 がある場合、Film の下にあるすべての顧客を照会したいとします。そのため、OrgId が 1 と 23 の両方を持つすべての顧客を取得する必要があります。

4

2 に答える 2

1

Linq はこれを支援しませんが、SQL Server は支援します。

CTE を作成して、次のような組織 ID のフラット化されたリストを生成します。

CREATE PROCEDURE [dbo].[OrganizationIds]
    @rootId int

AS
    WITH OrgCte AS 
    ( 
        SELECT OrganizationId FROM Organizations where OrganizationId = @rootId
        UNION ALL 
        SELECT parent.OrganizationId FROM Organizations parent
        INNER JOIN OrgCte child ON parent.Parent_OrganizationId = Child.OrganizationId
    ) 
    SELECT * FROM OrgCte 

RETURN 0

次に、このストアド プロシージャにマップされたコンテキストに関数インポートを追加します。これにより、コンテキストのメソッドが生成されます (元の Parent_OrganizationId が INT NULL として宣言されているため、返される値は null 許容の int です)。

public partial class TestEntities : ObjectContext
{
    public ObjectResult<int?> OrganizationIds(int? rootId)
    {
        ...

これで、次のようなクエリを使用できます。

// get all org ids for specific root.  This needs to be a separate 
// query or LtoE throws an exception regarding nullable int.
var ids = OrganizationIds(2);

// now find all customers
Customers.Where (c => ids.Contains(c.Organization.OrganizationId)).Dump();
于 2012-05-20T13:39:54.433 に答える
0

残念ながら、Entity Framework ではネイティブではありません。独自のソリューションを構築する必要があります。おそらく、ルートまで繰り返す必要があります。次のように、特定の数の親を一度に取得するように EF に依頼することで、このアルゴリズムを最適化できます。

...
select new { x.Customer, x.Parent.Customer, x.Parent.Parent.Customer }

このアプローチでは静的に固定された親の数 (ここでは 3) に制限されますが、データベースのラウンドトリップの 2/3 を節約できます。

編集:データモデルが正しくなかったと思いますが、アイデアが明確であることを願っています.

編集2:あなたのコメントと編集に応えて、私は次のようなアプローチを採用しました:

var rootOrg = ...;
var orgLevels = new [] {
 select o from db.Orgs where o == rootOrg, //level 0
 select o from db.Orgs where o.ParentOrg == rootOrg, //level 1
 select o from db.Orgs where o.ParentOrg.ParentOrg == rootOrg, //level 2
 select o from db.Orgs where o.ParentOrg.ParentOrg.ParentOrg == rootOrg, //level 3
};
var setOfAllOrgsInSubtree = orgLevels.Aggregate((a, b) => a.Union(b)); //query for all org levels

var customers = from c in db.Customers where setOfAllOrgsInSubtree.Contains(c.Org) select c;

これは、制限された最大ツリー深度に対してのみ機能することに注意してください。実際には、これは通常当てはまります (10 または 20 など)。

パフォーマンスは良くありませんが、これは LINQ-to-Entities 専用のソリューションです。

于 2012-05-20T09:11:47.013 に答える