2009-12-27 54 views
1

我不知道我做错了什么:“我认为我是”或我都创下了亚音速限制。 我有3个表文章,ArticleCategories和ArticleComments有一个到另一个表文章之间多对多的关系。 我已经创建了下面的类亚音速一对多的关系的子对象

public partial class Article 
{ 
    private string _CategoryName; 
    public string CategoryName 
    { 
     get { return _CategoryName; } 
     set 
     { 
      _CategoryName = value; 
     } 

    } 
    public ArticleCategory Category { get;set;} 
    private List<System.Linq.IQueryable<ArticleComment>> _Comments; 
    public List<System.Linq.IQueryable<ArticleComment>> Comments 
    { 
     get 
     { 
      if (_Comments == null) 
       _Comments = new List<IQueryable<ArticleComment>>(); 
      return _Comments; 
     } 
     set 
     { 
      _Comments = value; 
     } 
    } 

} 

我用这个片段

var list = new IMBDB().Select.From<Article>() 
      .InnerJoin<ArticleCategory>(ArticlesTable.CategoryIDColumn, ArticleCategoriesTable.IDColumn) 
      .InnerJoin<ArticleComment>(ArticlesTable.ArticleIDColumn,ArticleCommentsTable.ArticleIDColumn) 
      .Where(ArticleCategoriesTable.DescriptionColumn).IsEqualTo(category).ExecuteTypedList<Article>(); 

      list.ForEach(x=>x.CategoryName=category); 

      list.ForEach(y => y.Comments.AddRange(list.Select(z => z.ArticleComments))); 

我得到收集好的,但得到的文章的集合,当我尝试使用使用

foreach (IMB.Data.Article item in Model) 
的评论集

{

 %> 
<% 
     foreach (IMB.Data.ArticleComment comment in item.Comments) 
     { 

      %> 
     ***<%=comment.Comment %>*** 
     <%} 
    } %> 

的comment.Comment线引发此异常 无法转换类型的对象 'SubSonic.Linq.Structure.Query`1 [IMB.Data.ArticleComment]' 为类型“IMB.Data。 ArticleComment”。

我基本上是试图避免每次需要评论时都击中数据库。 是否有另一个实现这一目标? 谢谢

回答

2

好吧 - 我不是在做你正在尝试的东西,但希望这个例子能够让情况变得清晰一些。这是一起的我会怎么做一个连接使用亚音速,如果我绝对必须做这样的线路多。我认为这种方法唯一的办法是,如果我被一些第三方实施的对象和/或数据库模式的局限......

using System; 
using System.Collections.Generic; 
using System.Diagnostics; 
using System.Linq; 
using SubSonic.Repository; 

namespace SubsonicOneToManyRelationshipChildObjects 
{ 
    public static class Program 
    { 
     private static readonly SimpleRepository Repository; 

     static Program() 
     { 
      try 
      { 
       Repository = new SimpleRepository("SubsonicOneToManyRelationshipChildObjects.Properties.Settings.StackOverflow", SimpleRepositoryOptions.RunMigrations); 
      } 
      catch (Exception ex) 
      { 
       Console.WriteLine(ex); 
       Console.ReadLine(); 
      } 
     } 

     public class Article 
     { 

      public int Id { get; set; } 
      public string Name { get; set; } 

      private ArticleCategory category; 
      public ArticleCategory Category 
      { 
       get { return category ?? (category = Repository.Single<ArticleCategory>(single => single.Id == ArticleCategoryId)); } 
      } 

      public int ArticleCategoryId { get; set; } 

      private List<ArticleComment> comments; 
      public List<ArticleComment> Comments 
      { 
       get { return comments ?? (comments = Repository.Find<ArticleComment>(comment => comment.ArticleId == Id).ToList()); } 
      } 
     } 

     public class ArticleCategory 
     { 
      public int Id { get; set; } 
      public string Name { get; set; } 
     } 

     public class ArticleComment 
     { 
      public int Id { get; set; } 
      public string Name { get; set; } 

      public string Body { get; set; } 

      public int ArticleId { get; set; } 
     } 

     public static void Main(string[] args) 
     { 
      try 
      { 
       // generate database schema 
       Repository.Single<ArticleCategory>(entity => entity.Name == "Schema Update"); 
       Repository.Single<ArticleComment>(entity => entity.Name == "Schema Update"); 
       Repository.Single<Article>(entity => entity.Name == "Schema Update"); 

       var category1 = new ArticleCategory { Name = "ArticleCategory 1"}; 
       var category2 = new ArticleCategory { Name = "ArticleCategory 2"}; 
       var category3 = new ArticleCategory { Name = "ArticleCategory 3"}; 

       // clear/populate the database 
       Repository.DeleteMany((ArticleCategory entity) => true); 
       var cat1Id = Convert.ToInt32(Repository.Add(category1)); 
       var cat2Id = Convert.ToInt32(Repository.Add(category2)); 
       var cat3Id = Convert.ToInt32(Repository.Add(category3)); 

       Repository.DeleteMany((Article entity) => true); 
       var article1 = new Article { Name = "Article 1", ArticleCategoryId = cat1Id }; 
       var article2 = new Article { Name = "Article 2", ArticleCategoryId = cat2Id }; 
       var article3 = new Article { Name = "Article 3", ArticleCategoryId = cat3Id }; 

       var art1Id = Convert.ToInt32(Repository.Add(article1)); 
       var art2Id = Convert.ToInt32(Repository.Add(article2)); 
       var art3Id = Convert.ToInt32(Repository.Add(article3)); 

       Repository.DeleteMany((ArticleComment entity) => true); 
       var comment1 = new ArticleComment { Body = "This is comment 1", Name = "Comment1", ArticleId = art1Id }; 
       var comment2 = new ArticleComment { Body = "This is comment 2", Name = "Comment2", ArticleId = art1Id }; 
       var comment3 = new ArticleComment { Body = "This is comment 3", Name = "Comment3", ArticleId = art1Id }; 
       var comment4 = new ArticleComment { Body = "This is comment 4", Name = "Comment4", ArticleId = art2Id }; 
       var comment5 = new ArticleComment { Body = "This is comment 5", Name = "Comment5", ArticleId = art2Id }; 
       var comment6 = new ArticleComment { Body = "This is comment 6", Name = "Comment6", ArticleId = art2Id }; 
       var comment7 = new ArticleComment { Body = "This is comment 7", Name = "Comment7", ArticleId = art3Id }; 
       var comment8 = new ArticleComment { Body = "This is comment 8", Name = "Comment8", ArticleId = art3Id }; 
       var comment9 = new ArticleComment { Body = "This is comment 9", Name = "Comment9", ArticleId = art3Id }; 
       Repository.Add(comment1); 
       Repository.Add(comment2); 
       Repository.Add(comment3); 
       Repository.Add(comment4); 
       Repository.Add(comment5); 
       Repository.Add(comment6); 
       Repository.Add(comment7); 
       Repository.Add(comment8); 
       Repository.Add(comment9); 

       // verify the database generation 
       Debug.Assert(Repository.All<Article>().Count() == 3); 
       Debug.Assert(Repository.All<ArticleCategory>().Count() == 3); 
       Debug.Assert(Repository.All<ArticleComment>().Count() == 9); 

       // fetch a master list of articles from the database 
       var articles = 
        (from article in Repository.All<Article>() 
        join category in Repository.All<ArticleCategory>() 
         on article.ArticleCategoryId equals category.Id 
        join comment in Repository.All<ArticleComment>() 
         on article.Id equals comment.ArticleId 
        select article) 
        .Distinct() 
        .ToList(); 

       foreach (var article in articles) 
       { 
        Console.WriteLine(article.Name + " ID " + article.Id); 
        Console.WriteLine("\t" + article.Category.Name + " ID " + article.Category.Id); 

        foreach (var articleComment in article.Comments) 
        { 
         Console.WriteLine("\t\t" + articleComment.Name + " ID " + articleComment.Id); 
         Console.WriteLine("\t\t\t" + articleComment.Body); 
        } 
       } 

       // OUTPUT (ID will vary as autoincrement SQL index 

       //Article 1 ID 28 
       //  ArticleCategory 1 ID 41 
       //    Comment1 ID 100 
       //      This is comment 1 
       //    Comment2 ID 101 
       //      This is comment 2 
       //    Comment3 ID 102 
       //      This is comment 3 
       //Article 2 ID 29 
       //  ArticleCategory 2 ID 42 
       //    Comment4 ID 103 
       //      This is comment 4 
       //    Comment5 ID 104 
       //      This is comment 5 
       //    Comment6 ID 105 
       //      This is comment 6 
       //Article 3 ID 30 
       //  ArticleCategory 3 ID 43 
       //    Comment7 ID 106 
       //      This is comment 7 
       //    Comment8 ID 107 
       //      This is comment 8 
       //    Comment9 ID 108 
       //      This is comment 9   

       Console.ReadLine(); 

       // BETTER WAY (imho)...(joins aren't needed thus freeing up SQL overhead) 

       // fetch a master list of articles from the database 
       articles = Repository.All<Article>().ToList(); 

       foreach (var article in articles) 
       { 
        Console.WriteLine(article.Name + " ID " + article.Id); 
        Console.WriteLine("\t" + article.Category.Name + " ID " + article.Category.Id); 

        foreach (var articleComment in article.Comments) 
        { 
         Console.WriteLine("\t\t" + articleComment.Name + " ID " + articleComment.Id); 
         Console.WriteLine("\t\t\t" + articleComment.Body); 
        } 
       } 

       Console.ReadLine(); 

       // OUTPUT should be identicle 
      } 
      catch (Exception ex) 
      { 
       Console.WriteLine(ex); 
       Console.ReadLine(); 
      } 
     } 
    } 
} 

以下是我个人的意见和猜想,可以抛出/使用如你所见...

如果你看看“更好的方式”的例子,这更多的是我如何使用SubSonic。

亚音速是基于一些简单的原则,例如

  • 每个表是一个对象(类)
  • 每个对象实例具有ID(例如制品。ID)
  • 每个对象应该有一个名称(或类似)

现在,如果你写你的数据实体(你的类当您使用亚音速有能力的方式是有道理的表表示)你”作为一个团队一起工作会很好。当我使用SubSonic时,我并没有真的做任何加入,因为我通常不需要,也不需要开销。您开始展示一个很好的练习,即在您的文章对象上“延迟加载”注释列表属性。这很好,这意味着如果我们需要消费者代码中的评论,那就去获取。如果我们不需要评论,请不要花费时间&钱从数据库中获取它们。我以一种对我有意义的方式将文章类别重新组织为文章关系,但可能不适合您的需求。这似乎是你在概念上同意罗布(我再次同意他)。

现在,这个架构还有1000个其他改进。首先想到的是实现一个体面的缓存模式。例如,每次文章加载时,您可能都不想从每篇文章的数据库中提取评论。因此,您可能需要缓存文章和评论,如果添加了评论,请在“添加评论”代码中将文章从缓存擦除,以便重建下一次加载。类别是一个完美的例子...我通常会加载一些类似的东西(不可能每5分钟更改一次)到一个主Dictionary中(int是类别ID),并且只是从内存列表中引用我的文章代码。这些只是基本的想法,缓存,关系映射数据库或其他方面的概念可能会变得很复杂。我个人试图坚持SubSonic的思路,使数据库的生成和操作变得更加简单。

注意:如果您看一下Linq2SQL的操作方式,这种方法在最基本的层面上非常相似。 Linq2SQL通常每次都加载你的依赖关系,无论你是否想要它,或者知道它是否在做。如果你愿意,我更喜欢SubSonic的“显而易见性”,看看实际发生的事情。

对不起,我真的希望你可以在一个小小的控制台应用程序中运行上面的代码,并感受一下我所得到的。

+0

戴夫,当我做了推荐的更改,我得到一个演员异常 – Sammy 2009-12-28 00:00:07

+0

相同的代码工作正常在同一地点相同的演员异常? – 2009-12-28 00:23:03

+0

不能从 System.Collections.Generic.IEnumarable >转换为 System.Collections.Generic.IEnumarable 引起这行 列表.ForEach(y => y.Comments.AddRange(list.Select(z => z.ArticleComments))); – Sammy 2009-12-28 00:44:24

1

首先想到的是,不应该类别协会是相反的?类别有很多文章?我不知道这是否会对我有帮助 - 这是我的第一次观察。

我认为你在这里有一个命名冲突。 A“Structure.Query”是我们对Structs.tt创建一个对象,它看起来像这就是你用“item.Comments”莫名其妙引用的命名空间。我的猜测是有一个名为“评论”的表格让人感到困惑。

你可以打开文章类,看看“评论”属性的返回,以确保它返回一个类型,而不是查询?

+1

Rob您对类别和文章之间的关系是正确的。 我仍然不能得到类别对象“我检查了返回类型及其正确的类型”。 我仍然将Article.Category设置为null。在亚音速2.1 – Sammy 2009-12-27 23:59:02