2

次のデータベース構造が与えられた場合、 代替テキストhttp://dl.dropbox.com/u/26791/tables.png

関連付けられているタグでグループ化された画像を返すLINQクエリを作成しようとしています。これまでのところ私はこれを持っています:

var images = from img in db.Images
    join imgTags in db.ImageTags on img.idImage equals imgTags.idImage
    join t in db.Tags on imgTags.idTag equals t.idTag
    where img.OCRData.Contains(searchText.Text)
    group img by new { t.TagName } into aGroup
    select new
    {
        GroupName = aGroup.Key.TagName,
        Items = from x in aGroup
        select new ImageFragment()
        {
             ImageID = x.idImage,
             ScanDate = x.ScanTime
        }
    };

これはうまくいきます。ただし、「(タグなし)」などのグループでタグが関連付けられていない画像も返したいです。すべての画像にデフォルトのタグを挿入せずにこれを行う方法に頭を悩ませることはできません。これは一般的にあまり良い解決策ではないようです。

4

3 に答える 3

1

対応するタグレコードがないときに画像レコードが必要な場合は、画像タグテーブルで
外部結合を実行する必要があります。

于 2010-04-02T02:08:32.470 に答える
0

少し注意が必要ですが、 linqが動作する新しいインスタンスImageTagとインスタンスをインスタンス化する機能がある場合は、1つの大きなクエリでそれを行うことができます。Tag基本的に、外部結合を行う場合はinto、メソッドでキーワードを使用DefaultIfEmpty(...)して「外部結合ギャップ」を処理する必要があります(たとえば、通常のSQL左外部結合で結合キーの右側がnullの場合)。 。

var images=db.Imagesのimgから
     img.idImageのdb.ImageTagsにimgTagsを結合すると、imgTags.idImageと等しくなります
     outerImageRefに
     externalImageRef.DefaultIfEmpty(new ImageTag(){idImage = img.idImage、idTag = -1})のouterIRから
     imgTags.idTagのdb.Tagsにtを結合するとt.idTagと等しくなります
     outerRefTagsに
     externalRefTags.DefaultIfEmpty(new Tag(){idTag = -1、TagName = "untagged"})のouterRTから
     imgをouterRT.TagNameでaGroupにグループ化します
     新しい{を選択します
         GroupName = aGroup.Key、
         アイテム=aGroupのxから
             新しいImageFragment()を選択します{
                 ImageID = x.idImage、
                 ScanDate = x.ScanTime
             }
     };

正確な環境がないため、上記のコンパイルがうまくいけば、独自のデータ型を使用してソリューションを構築し、それを質問の説明に変換しました。基本的に重要な部分は、従来のSQLの意味で考えている場合に、メモリ内にある大規模に結合されたテーブルに余分な「行」を追加するのに本質的に役立つ余分な行ですintoDefaultIfEmpty

ただし、linqエンティティのメモリ内インスタンス化を必要としないより読みやすいソリューションがあります(これを自分の環境に変換する必要があります)。

//この最初のクエリは、TagNameとImageIdを持つ匿名タイプのコレクションを返します。
//基本的にImageTagsx-refテーブルとTagsを結合することからの関係
//各行はタグと画像IDです(Robert HarveyがQへのコメントで述べたように)
vartagNamesWithImageIds=タグ内のタグから
       tag.IdTagのImageTagsでreferを結合します。refer.IdTagと同じです。
       新しい{を選択します
           TagName = tag.Name、
           ImageId = refer.IdImage
       };
//これで、画像を上記の関係に外部結合することでソリューションを取得できます
//そして「外部結合ギャップ」を再び「タグなし」の匿名タイプで埋めます
//次に、それをもう一度Imagesテーブルに結合して、グループ化と投影を取得します。
var images = from img in Images
     img.IdImageのtagNamesWithImageIdsのtをt.ImageIdに等しくします
     アウタージョインに
     からouterJoin.DefaultIfEmpty(new {TagName = "untagged"、ImageId = img.IdImage})
     o.ImageIdの画像でimg2を結合するとimg2.IdImageと等しくなります
     img2をo.TagNameでaGroupにグループ化します
     新しい{を選択します
         TagName = aGroup.Key、
         Images = aGroup.Select(i => i.Data).ToList()//これをコードのロジックに置き換える必要があります。ワークスペースには、はるかに単純なデータ型がありました。
     };

それが理にかなっていることを願っています。もちろん、いつでもアプリケーションをデフォルトで「タグなし」ですべてにタグ付けするように設定するか、もっと単純なLINQクエリを実行して、ImageTagテーブルに存在しない画像IDのリストを作成し、次にユニオンなどを作成することができます。

于 2010-04-02T21:55:05.983 に答える
0

これが私がやったことです。これがどのようなSQLを生成しているのかはまだ確認していませんが、おそらく正確にはきれいではないと思います。いくつかのクエリを実行して自分で集計したほうがいいと思いますが、いずれにせよ、これは機能します。

var images = from img in db.Images
                     join imgTags in db.ImageTags on img.idImage equals imgTags.idImage into g
                     from imgTags in g.DefaultIfEmpty()
                     join t in db.Tags on imgTags.idTag equals t.idTag into g1
                     from t in g1.DefaultIfEmpty()
                     where img.OCRData.Contains(searchText.Text)
                     group img by t == null ? "(No Tags)" : t.TagName into aGroup
                     select new
                    {
                        GroupName = aGroup.Key,
                        Items = from x in aGroup
                                        select new ImageFragment()
                                        {
                                            ImageID = x.idImage,
                                            ScanDate = x.ScanTime
                                        }
                    };
于 2010-04-03T05:41:56.807 に答える