我正在尝试升级旧的CMS以使用NHibernate,并且无法阻止原始数据库结构。这是造成问题的一点。假设我有以下两个表:
Articles:
- Id (PK, Identity)
- Title
- Content
Meta:
- ArticleId (PK, FK to Articles)
- Description
- Keywords
我创建了以下类:
public class Article {
public virtual int Id { get; set; }
public virtual string Title { get; set; }
public virtual string Content { get; set; }
}
public class Meta : IComponent {
public virtual string Description { get; set; }
public virtual string Keywords { get; set; }
}
public interface IComponent {
}
通常,Meta通常会被映射为Article类的组件(或一对一关系)属性。但是,在我正在构建的应用程序中,管理员可以启用/禁用适用于文章的组件。此外,我希望他们扩展应用程序以添加自己的组件,而无需触及Article类。
因为他们无法为Article类添加属性。现在理想情况下,在我的代码中,我希望能够说:
var articles = session.Query<Article>()
.Fetch(a = a.Component<Meta>())
.Where(a => a.Component<Meta>().Keywords.Contains("Some Word"))
.ToList();
// This wouldn't generate an extra SQL statement
var keywords = articles[0].Component<Meta>().Keywords;
哪会产生以下SQL(或类似):
SELECT * FROM Articles INNER JOIN Meta ON Articles.Id = Meta.ArticleId WHERE Meta.Keywords LIKE'%Some Word%'
是否可以映射Component方法,以便它进行内连接以获取Meta。这个概念看起来很简单,但我不知道从哪里开始。我非常感谢你的帮助。
谢谢
答案 0 :(得分:0)
在NHibernate映射文件中,您可以指定获取类型。一对一xml的规范位于NHibernate Documentation。请注意,数字5有一个选择加入和选择,它默认选择。
答案 1 :(得分:0)
鉴于此:
public class Article
{
public virtual int ArticleId { get; set; }
public virtual string Title { get; set; }
public virtual string Content { get; set; }
}
public class Meta : IComponent
{
public virtual Article Article { get; set; }
public virtual int MetaId { get; set; }
public virtual string Description { get; set; }
public virtual string Keywords { get; set; }
}
AFAIK,您无法获取不属于实体的内容。因此,从您的示例中,无法从Article实体中获取Meta。
因此,如果您想获取文章的其他信息,您只需要将文章加入其中,然后在Linq中投影完整数据,例如:
var articles =
from a in s.Query<Article>()
join m in s.Query<Meta>() on a equals m.Article
where m.Keywords.Contains("Some Word")
select new { a, m };
foreach(var x in articles)
Console.WriteLine("{0} {1}", x.a.Title, x.m.Description);
结果查询:
select *
from [Article] article0_, [Meta] meta1_
where meta1_.ArticleId = article0_.ArticleId
and meta1_.Keywords like '%Some Word%'
另一种方法,从Meta开始,然后获取文章;在查询时,这将立即加入文章,即没有延迟加载:
var artB =
from m in s.Query<Meta>().Fetch(x => x.Article)
where m.Keywords.Contains("Some Word")
select m;
foreach (var x in artB)
Console.WriteLine("{0} {1}", x.Article.Title, x.Description);
结果查询:
select *
from [Meta] meta0_
left outer join [Article] article1_ on meta0_.ArticleId = article1_.ArticleId
where meta0_.Keywords like '%Some Word%'
要保留只有一个Meta的文章,请在Meta的参考文献中添加一个唯一:
create table Article
(
ArticleId int identity(1,1) not null primary key,
Title varchar(100) not null,
Content varchar(100) not null
);
create table Meta
(
-- this prevents an Article having two Meta
ArticleId int not null references Article(ArticleId) unique,
MetaId int identity(1,1) not null primary key,
Description varchar(100) not null,
Keywords varchar(100) not null
);
insert into Article(Title,Content) values('Great','Yeah')
insert into Meta(ArticleId, Description, Keywords) values(1,'Oh','Some Word');
答案 2 :(得分:0)
以下解决方案是否会引起关注?
您可以对组件进行受保护的映射,并从此公共泛型方法访问这些映射。
通过这种方式,您可以选择加载/延迟加载组件。
public class Article
{
protected virtual ICollection<IComponent> Components { get; set; }
public virtual T Component<T>() where T : IComponent
{
return Components.FirstOrDefault(c=>c.Type==typeof(T));
}
}