我不知道我做错了什么“我想我是”或者我已经达到亚音速限制。 我有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)));
我收集了Ok,但是当我尝试使用
的评论集时 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'。
我基本上是在每次需要评论时都试图避免访问数据库。 是否有另一个实现这一目标? 感谢
答案 0 :(得分:2)
好的 - 我并没有完全按照你的意思行事,但希望这个例子可以为这种情况带来一些清晰度。这更像是我如何使用SubSonic进行连接,如果我绝对必须这样做的话。我考虑这种方法的唯一方法是,如果我受到对象和/或数据库模式的某些第三方实现的限制......
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的方式。
SubSonic基于一些简单的原则,例如
现在,如果您在使用SubSonic时以一种有意义的方式编写数据实体(表示表的表示),那么您将作为一个团队一起工作。我在使用SubSonic时并没有真正做任何连接,因为我通常不需要,而且我不想要开销。您开始在文章对象上显示“延迟加载”注释列表属性的良好做法。这很好,这意味着如果我们需要消费者代码中的注释,请转到get-em。如果我们不需要评论,请不要花时间和钱要从数据库中取出来。我以一种对我有意义的方式将ArticleCategory重组为Article关系,但可能不适合您的需求。看起来你在概念上同意了Rob(我再次同意他的意见)。
现在,该架构还有1000项其他改进。首先想到的是实现一个体面的缓存模式。例如,每次加载文章时,您可能不希望从每篇文章的数据库中获取注释。因此,您可能希望缓存文章和评论,如果添加了评论,则在“添加评论”代码中,从缓存中擦除文章,以便下次加载时重建。类别就是一个完美的例子...我通常会将类似(类似于每5分钟不可能改变的东西)加载到一个主词典中(int是类别ID)并且只引用内存列表来自我的文章代码。这些只是基本的想法,缓存,关系映射数据库或其他方面的概念可以随意变得复杂。我只是亲自尝试遵循SubSonic的心态,使数据库生成和操作变得更加容易。
注意:如果你看一下Linq2SQL的工作方式,这种方法在最基本的层面上非常相似。 Linq2SQL通常每次加载您的依赖关系,无论您是否想要它或知道它是否正在这样做。如果你愿意的话,我更喜欢SubSonic的“显而易见性”,即实际发生的事情。
很抱歉这个咆哮,但我真的希望你能在一个小的控制台应用程序中运行上面的代码,并了解我所得到的。
答案 1 :(得分:1)
首先想到的是,类别关联不应该是另一种方式吗?类别有很多文章吗?我不知道这是否有帮助 - 这是我的第一次观察。
我认为你在这里遇到了命名冲突。 “Structure.Query”是我们在Structs.tt上创建的对象,它看起来像是你用“item.Comments”以某种方式引用的命名空间。我的猜测是有一个名为“评论”的桌子让人感到困惑。
你能打开Article类并查看“Comments”属性的返回,以确保它返回一个类型,而不是查询吗?