1

この質問は主にLINQと共分散に関するものです。

私のエンティティのうち 2 つは、 IDatedItemインターフェイスを実装しています。単一のリストとして列挙するために、これらを結合して並べ替えたいと思います。列挙時にエンティティ固有のプロパティを保持する必要があります。

例で明確にするために、私が試した1つのアプローチは次のとおりです。

Context.Table1.Cast<IDatedItem>().
Union(Context.Table2.Cast<IDatedItem>()).
SortBy(i => i.Date).
ForEach(u => CustomRenderSelector(u, u is Table1));

これをさまざまな方法で実行しようとすると、さまざまなエラーが発生しました。

  • LINQ to Entities は、EDM プリミティブ型または列挙型のキャストのみをサポートします。
  • タイプ '.IDatedItem[]' を処理できません。値レイヤーへの既知のマッピングはありません
  • タイプ 'IDatedItem' の定数値を作成できません。プリミティブ型のみ

全体像:

  • ここに示す IDatedItem インターフェイスは、実際の共有プロパティを簡略化したものです。
  • 実際には、テーブルはユニオンの前にフィルター処理されます。
  • エンティティ固有のプロパティは、順番に Web ページにレンダリングされます。
  • 並列機能では、JSON 結果階層にシリアル化されます。
  • 結果に対してもLINQ集計操作を実行できるようにしたいと思います。
4

2 に答える 2

1

これには、コメントが提供するよりも多くのスペースが必要です。一方で、満足のいく答えはないので、これは本当の答えではありません。

aUnionが成功するためには、両方のコレクションが同じ型でなければなりません (または、共通の型への組み込みの変換が必要です。それが共分散です)。

したがって、正しいユニオンを取得するための最初の試みは次のようになります。

Context.Table1.Select(t1 => new {
                                    A = t1.PropA,
                                    B = t1.PropB,
                                    Date = t1.Date
                                })
.Union(
Context.Table1.Select(t2 => new {
                                    A = t2.PropC,
                                    B = t2.PropD,
                                    Date = t2.Date
                                }))
.OrderBy(x => x.Date)
.ToList();

両方のテーブルを同じ匿名型に射影します。残念ながら、匿名型のため、できません.Cast<IDatedItem>()

したがって、 を取得する唯一の方法は、両方のテーブルをList<IDatedItem>実装してその型に射影する型を定義することです。IDatedItem

Context.Table1.Select(t1 => new DateItem {
                                    A = t1.PropA,
                                    B = t1.PropB,
                                    Date = t1.Date
                                })
.Union(
Context.Table1.Select(t2 => new DateItem {
                                    A = t2.PropC,
                                    B = t2.PropD,
                                    Date = t2.Date
                                }))
.OrderBy(item => item.Date)
.AsEnumerable()
.Cast<IDatedItem>()

これは(私が思うに)非常に精巧です。しかし、EF が linq クエリでのインターフェイスへのキャストをサポートしていない限り、それは道のりです。

ちなみに、コメントで言ったのとは逆に、ソートはSQLで行います。そして、結果に対して後続の集計関数を使用できます。

于 2013-08-24T11:57:13.450 に答える
0

これが作業コードです。私の解決策は、すべてのデータがローカルであることを確認し、LINQ-to-EF が多くの不明なエラーを引き起こしていることがわかっている、できないことがわかっているあらゆる種類のことを実行しようとしないようにすることでした。次に、ジェネリック Union での単純な型宣言が定着します。

つまり、LINQ から EF への煩わしさは別として、ここでの主な問題は実際にはLINQ Union のさまざまな型の複製であり、インターフェイスへの動的キャストですか? .

public virtual ActionResult Index() {
    return View(StatusBoard().OrderBy(s => s.Status));
}

private IEnumerable<DefensiveSituationBoardMember> StatusBoard() {
    DateTime now = DateTime.UtcNow;
    DateTime historicalCutoff = now.AddDays(-1);
    IEnumerable<Member> activeMembers = Context.Members.Where(n => !n.Disabled).ToList();

    // IncomingAttack and Reinforcements both implement IDefensiveActivity
    IEnumerable<IncomingAttack> harm = Context.IncomingAttacks.Where(n => n.IsOngoingThreat || n.ArrivalOn > historicalCutoff).ToList();
    IEnumerable<Reinforcements> help = Context.Reinforcements.Where(n => !n.Returned.HasValue || n.Returned > historicalCutoff).ToList();

    // Here's the relevant fix
    IEnumerable<IDefensiveActivity> visibleActivity = help.Union<IDefensiveActivity>(harm);

    return from member in activeMembers
        join harmEntry in harm on member equals harmEntry.DestinationMember into harmGroup
        join activityEntry in visibleActivity on member equals activityEntry.DestinationMember into activityGroup
        select new DefensiveSituationBoardMember {
            Member = member,
            Posture = harmGroup.Max(i => (DefensivePostures?)i.Posture),
            Activity = activityGroup.OrderBy(a => a.ArrivalOn)
        };

}
于 2013-08-25T00:35:24.470 に答える