0

LINQ2SQLを学び始めたばかりで、最初に試したかったことの1つは単純な親子階層ですが、それを行うための良い方法を見つけることができないようです。私はここSOでいくつかの例を見て、グーグルで検索しましたが、それらを直接適用することができなかったので、私が達成しようとしていることを正確に説明します。

タグ付きの一般的な例を使用してみましょう。

データベーステーブル:Post--Post_Tags-タグ

単純なPostクラスを作成したので、Linq2Sqlクラスを渡さないようにします。

public class Post
{
    public int Id {get; set;}
    public int Title {get; set;}
    public IEnumerable<string> Tags {get; set;}
}

Postsテーブルから最新の5つのレコードを選択し、それらに関連するタグを取得して、各PostのTagsプロパティが入力されているIListを返します。

具体的なLinq2Sqlコードを教えていただけますか?

私は試した:

      IList<Post> GetLatest()
      {
            return (from p in _db.Posts
                   orderby p.DateCreated descending
                   select new Post
                   {
                       Id = p.Id,
                       Title = p.Title,
                       Tags = p.Post_Tags.Select(pt => pt.Tag.Name)
                   }).Take(5).ToList();
       }

これは機能しますが、タグレコードごとにPostレコードを複製するため、ユーザーが使用するすべてのメソッドでプロパティマッピング(Id = p.Id、...)を複製する必要があります。次に、このアプローチを試しましたが、この場合、すべてのタグについてDBへのラウンドトリップがあります。

      IQueryable<Post> GetList()
      {
            return (from p in _db.Posts
                   select new Post
                   {
                       Id = p.Id,
                       Title = p.Title,
                       Tags = p.Post_Tags.Select(pt => pt.Tag.Name)
                   });
       }

      IList<Post> GetLatest()
      {
            return (from p in GetList()
                   orderby p.DateCreated descending
                   select p).Take(5).ToList();
       }

従来のADO.NETで実行している場合は、2つの結果セットを返すストアドプロシージャを作成します。1つは投稿レコード、もう1つは関連するタグレコードです。次に、それらをコードにマップします(手動、DataRelation、ORMなど)。LINQ2SQLでも同じことができますか?

このような単純な階層をどのように処理するかについて、いくつかのコードサンプルを見るのは本当に興味があります。

はい、IList <>オブジェクトとカスタムクラスを返したいのですが、クエリ可能なLinq to Sqlオブジェクトではありません。たとえば、Linq2Sqlを放棄する場合は、データアクセスコードに柔軟性を持たせたいからです。

ありがとう。

4

3 に答える 3

1

DataContextを作成すると、親子関係が自動的に維持されます。

つまり、Linq2Sql DataContext内で投稿とタグ、およびそれらの関係をモデル化すると、次のように投稿をフェッチできます。

var allPosts = from p in _db.Posts
               orderby p.DateCreated descending
               select p;

そうすれば、次のように変数pのメンバーとしてアクセスできるため、タグについてまったく心配する必要はありません。

var allPostsList = allPosts.ToList();

var someTags = allPostsList[0].Post_Tags;
var moreTags = allPostsList[1].Post_Tags;

そして、SubmitChanges()を要求するまで、繰り返されるインスタンスはDataContext全体で自動的に更新されます。

IMO、それがORMのポイントです。ORMによってすべての関係を管理する必要があるため、モデルクラスを再作成したり、多くの場所でマッピングを維持したりする必要はありません。

ラウンドトリップに関しては、データベースへのトリップを明示的に要求するコードを控えると、すべてのクエリは中間クエリ表現に格納され、データが実際に続行する必要がある場合にのみ、クエリがSQLに変換されます結果を取得するためにデータベースにディスパッチされます。

つまり、次のコードはデータベースに1回だけアクセスします

 // these 3 variables are all in query form until otherwise needed
 var allPosts = Posts.All();
 var somePosts = allPosts.Where(p => p.Name.Contains("hello"));
 var lesserPosts = somePosts.Where(p => p.Name.Contains("World"));

 // calling "ToList" will force the query to be sent to the db
 var result = lesserPosts.ToList();
于 2009-03-01T16:00:33.730 に答える
0
List<Post> latestPosts = db.Posts
  .OrderByDescending( p => p.DateCreated )
  .Take(5)
  .ToList();

  // project the Posts to a List of IDs to send back in
List<int> postIDs = latestPosts
  .Select(p => p.Id)
  .ToList();

// fetch the strings and the ints used to connect 
ILookup<int, string> tagNameLookup = db.Posts
  .Where(p => postIDs.Contains(p.Id))
  .SelectMany(p => p.Post_Tags)
  .Select(pt => new {PostID = pt.PostID, TagName = pt.Tag.Name } )
  .ToLookup(x => x.PostID, x => x.TagName);
//now form results
List<Post> results = latestPosts
  .Select(p => new Post()
  {
    Id = p.Id,
    Title = p.Title,
    Tags = tagNameLookup[p.Id]
  })
  .ToList();
于 2009-05-12T20:05:33.260 に答える
0

最初にDataLoadOptionsを設定して、投稿でタグを明示的に読み込むとどうなりますか? 何かのようなもの:

IList<Post> GetLatest()
{
     DataLoadOptions options = new DataLoadOptions();
     options.LoadWith<Post>(post => post.Tags);
     _db.LoadOptions = options;

     return (from p in _db.Posts
             orderby p.DateCreated descending)
             Take(5).ToList();
   }
于 2009-03-01T16:37:54.950 に答える