2009-03-01 59 views
0

我刚开始学习LINQ2SQL,我想尝试的第一件事情是简单的父子层次结构,但似乎找不到一个好办法。我在这里看到了一些例子,并且我已经使用了Google,但是我不能直接应用它们,所以我会解释我想要完成的工作。与LINQ2SQL和POCO对象的亲子关系

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

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

我创建了一个简单的邮政类,所以我尽量避免周围路过LINQ2SQL类:

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

我想选择5个最新记录Posts表格,获取他们的相关标签并返回IList,其中每个Post都有其标签属性填充。

你能告诉我一个具体的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(); 
     } 

这工作,但复制发表记录每个标签记录,我在每一个方法,我的用户复制属性映射(ID = p.Id,...)。然后,我尝试这种方法,但在这种情况下,我有一个往返到数据库为每个变量:

 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 to Sql对象,因为我想灵活地了解数据访问代码,例如,如果我决定放弃Linq2Sql。

谢谢。

回答

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

至于往返,如果从明确请求访问数据库的任何代码避免,所有查询都将被存储在一个中间查询表示,只有实际需要的数据继续,是当该查询将被转换为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(); 
+0

谢谢您的回答,但最重要的,这是我不希望靠LINQ2SQL课后的DAL。 – muerte 2009-03-01 16:08:10

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(); 
    } 
+0

我试了一下,它仍然n次到数据库。我不能做post => post.Tags,但post => post.Post_Tags – muerte 2009-03-01 16:43:31

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(); 
+0

因此,这将做2次往返数据库? – 2009-06-04 01:49:52