与LINQ2SQL和POCO对象的父子关系

时间:2009-03-01 15:46:42

标签: sql linq-to-sql tags parent-child hierarchy

我刚开始学习LINQ2SQL,我想要尝试的第一件事就是一个简单的父子层次结构,但我似乎无法找到一个好方法。我在这里看到了一些例子,我用Google搜索,但我不能直接应用它们,所以我将准确解释我想要完成的事情。

让我们使用带标签的常见示例。

数据库表:Post-- Post_Tags - 标签

我创建了一个简单的Post类,所以我避免传递Linq2Sql类:

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

我想从帖子表中选择5条最新记录,获取相关标签并返回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();
       }

这可以工作但是复制每个Tag记录的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中这样做,我会创建一个返回两个结果集的存储过程。一个有Post记录,另一个有相关的Tag记录。然后我会在代码中(通过DataRelation,ORM等手工映射它们)。我可以用LINQ2SQL做同样的事吗?

我真的很想看到一些关于你们如何处理这种简单层次结构的代码示例。

是的,我真的想退回IList&lt;&gt;对象和我的自定义类,而不是可查询的Linq到Sql对象,因为如果我决定放弃Linq2Sql,我想对数据访问代码保持灵活。

感谢。

3 个答案:

答案 0 :(得分: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;

然后在整个DataContext中自动更新任何重复的实例,直到您要求它提交SubmitChanges();

IMO,这是ORM的重点,您不需要重新创建模型类并在多个地方维护映射,因为您希望ORM为您管理所有这些关系。 < / p>

对于往返,如果您避免显式请求访问数据库的任何代码,则所有查询将存储在中间查询表示中,并且只有 时实际需要数据才能继续,是将查询转换为sql并分派到数据库以获取结果。

即。以下代码仅访问数据库一次

 // 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();

答案 1 :(得分: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();
   }

答案 2 :(得分: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();