在运行时一对一关系映射 [英] Map One to One Relationship at Run-Time

查看:112
本文介绍了在运行时一对一关系映射的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将旧的CMS升级为使用NHibernate,并且不能太大地偏离原始数据库结构.这是引起问题的位.说我有以下2个表:

i'm trying to upgrade an old CMS to use NHibernate and can't deter from the original database structure much. Here is the bit which is causing an issue. Say i have the following 2 tables:

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类.

Usually the Meta would normally be mapped as a component (or a one to one relationship) property on the Article class. However in the application i'm building an admin can enable/disable the components that apply to articles. Also i'd like them to extend the application to add their own components without touching the Article class.

由于它们的原因,我无法对Article类添加属性.现在,理想情况下,在我的代码中我想说:

For them reasons i can't add a property against the Article class. Now ideally in my code i'd like to be able to say:

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(或类似的SQL):

Which would generate the following SQL (or similar):

选择*从文章内部加入Metas on Articles.Id = Meta.ArticleId WHERE Meta.Keywords喜欢'%Some Word%'

SELECT * FROM Articles INNER JOIN Meta ON Articles.Id = Meta.ArticleId WHERE Meta.Keywords LIKE '%Some Word%'

是否可以映射Component方法,使其进行内部联接以获取Meta.这个概念似乎很简单,但是我不知道从哪里开始.我非常感谢您的帮助.

Is it possible to map the Component method so that it does an inner join to get the Meta. The concept seems pretty simple but i don't have a clue where begin. I'd really appreciate the help.

谢谢

推荐答案

为此:

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.

AFAIK, you cannot Fetch something that isn't part of an entity. So from your example, it's not possible to fetch Meta from the Article entity.

因此,如果您想获取文章的其他信息,只需将文章加入其中,然后在Linq中投影完整的数据,例如:

So if you want to fetch the other info of an Article, you just have to join Article to them, then project the complete data in your Linq, example:

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开始,然后获取Article;根据查询,这将立即加入文章,即无需延迟加载:

Another approach, start from Meta, then fetch the Article; on query, this will join the Article immediately, i.e. no lazy loading:

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的引用上添加一个Unique:

To keep an Article having only one Meta, put a Unique on Meta's reference:

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');

这篇关于在运行时一对一关系映射的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆