0

我刚开始学习 LINQ2SQL,我想尝试的第一件事是简单的父子层次结构,但我似乎找不到一个好的方法。我在 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 条最新记录,获取它们的相关标签并返回 IList,其中每个 Post 都填充了 Tags 属性。

你能给我看一个具体的 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<> 对象和我的自定义类,而不是可查询的 Linq 到 Sql 对象,因为如果我决定放弃 Linq2Sql,我希望对数据访问代码保持灵活。

谢谢。

4

3 回答 3

1

如果您创建 DataContext,则会自动为您维护父子关系。

即,如果您在 Linq2Sql DataContext 中对 Posts 和 Tags 及其关系进行建模,则可以像这样获取帖子:

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 为您管理所有这些关系。

至于往返,如果您避免使用任何显式请求访问数据库的代码,则所有查询都将存储在中间查询表示中,并且只有实际需要数据继续时,才会将查询转换为 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();
于 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 回答