2016-04-26 22 views
4

私は、Idのような主キーとLastMeterReadingId(同じテーブルを参照する外部キー)のような列を含むテーブルを持っています - 親メーターの読み方のようなものです。自己参加型LINQでのクエリ

That's how it's looks like

私はすでに親のように使用されていないすべての行を取得したいと思います。私はメートルの読みが1メートル以上の読書の親である状況を避けたいです。

私は同じテーブルに参加する方法を知っていますが、すでに親ではないレコードだけを選択する方法はわかりません。これは、条件文なしでクエリがどのように見えるかです。

return (from m in uow.MeterReadingReadWriteRepository.Query() 
       join parent in uow.MeterReadingReadWriteRepository.Query() on m.Id equals parent.LastMeterReadingId 

       select new MeterReadingDto() 
       { 
        (...) 
       }).ToList(); 

効果的な方法で実現する方法はありますか?

よろしくお願いいたします。

+0

通常、このように、テーブルを列挙する再帰的なメソッドを記述します。 Linqは親の子の参加には問題ありませんが、複数世代のLINQでは良い結果は得られません。 – jdweng

+0

まず、私はこれが通常の形に違反していると主張します。メーターの読書は、単にメーターの読書日によってソートすることによって得ることができる別の情報の子であるかどうかではないからです。また、連鎖してチェーンの途中でレコードを削除するとどうなりますか?あなたはその事件でちょっとねじれていませんか? –

答えて

6

私はすでに別の言い方をすれば親

のように使用されていないすべての行を取得したいと思い、あなたは子を持たないすべての行をしたいです。クエリの変数名parentが誤解を招くことに注意してください。a join b on a.Id equals b.ParentIdを実行すると、aが親で、bが子です。とにかく

、IMO(すなわち均等に効率的でなければなりません)、今日のデータベースクエリ・オプティマイザからの視点等価である、あなたの目標を達成するには、少なくとも3つの方法があります。

(1)SQLと同じです!Any(...)を使用してNOT EXISTS(...)

from m in uow.MeterReadingReadWriteRepository.Query() 
where !uow.MeterReadingReadWriteRepository.Query().Any(child => m.Id == child.LastMeterReadingId) 
select ... 

(2)group join使用:

from m in uow.MeterReadingReadWriteRepository.Query() 
join child in uow.MeterReadingReadWriteRepository.Query() 
on m.Id equals child.LastMeterReadingId into children 
where !children.Any() 
select ... 

(3)除外使用アンチ結合ER:これはEF(エンティティへのLINQ)であれば

from m in uow.MeterReadingReadWriteRepository.Query() 
join child in uow.MeterReadingReadWriteRepository.Query() 
on m.Id equals child.LastMeterReadingId into children 
from child in children.DefaultIfEmpty() 
where child == null 
select ... 

、最初の二つは、1と同じSQL NOT EXISTSベースのクエリに変換されます。最後は "従来の" SQL LEFT JOIN ... WHERE right.PK IS NULLベースのクエリに変換されます。

0

あなただけ

where !(from child in uow.MeterReadingReadWriteRepository.Query() where child.Id == m.LastMeterReadingId select child).Any()

これはしかし、最適化される方法インテリジェントわからないを追加することができます。 uow.MeterReadingReadWriteRepository.Query()を除外する方が良いでしょう。

Meter Readingエンティティに外部キー制約の子関係/コレクションがありませんか?これにより、クエリがはるかに簡単になります。

0
var readings = uow.MeterReadingReadWriteRepository.Query(); 

var parents = readings 
     .Join(readings, child => child.Id, parent => parent.LastMeterReadingId, 
       (child, parent) => new {parent.Id}) 
     .Distinct() 
     .ToDictionary(a => a.Id); 

var result = (from m in readings 
        where !parents.Contains(m.Id) 
        select new 
        { 
         Id = m.Id 
        }).ToList(); 
0

おかげ@Benジャクソン最も値のプロパティがどのように見えるかだ

public class MeterReading : EntityBase 
{ 
    public long PropertyId { get; set; } 
    public long? LastMeterReadingId { get; set; } 
    public long? PaymentId { get; set; } 
    public Property Property { get; set; } 
    public MeterReading LastReading { get; set; } 
    public Payment Payment { get; set; } 
} 

。たぶん、条件文の前に記載されているCTEにJOINを使用してT-SQLクエリを使用する必要がありますか?私はすぐにあなたのソリューションを試してみます。