Родительско-дочерние отношения с объектами LINQ2SQL и POCO - PullRequest
0 голосов
/ 01 марта 2009

Я только начал изучать 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;}
}

Я хотел бы выбрать 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();
       }

Это работает, но дублирует записи Post для каждой записи Tag, и мне приходится дублировать сопоставление свойств (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 в Sql, потому что я хотел бы проявлять гибкость в отношении кода доступа к данным, если я, например, решу отказаться от Linq2Sql.

Спасибо.

Ответы [ 3 ]

1 голос
/ 01 марта 2009

Если вы создаете 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 голосов
/ 13 мая 2009
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 голосов
/ 01 марта 2009

Как насчет того, чтобы сначала установить 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();
   }
...