在运行时映射一对一关系

发布于 2024-11-18 07:10:53 字数 1325 浏览 4 评论 0原文

我正在尝试升级旧的 CMS 以使用 NHibernate,并且无法对原始数据库结构产生太大影响。这是导致问题的部分。假设我有以下 2 个表:

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.这个概念看起来很简单,但我不知道从哪里开始。我真的很感激你的帮助。

谢谢

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 

I have created the following classes:

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 {
}

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.

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;

Which would generate the following SQL (or similar):

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

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.

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

蓦然回首 2024-11-25 07:10:54

以下解决方案会引起您的兴趣吗?

您可以对组件进行受保护的映射,并从此公共通用方法访问这些组件。

这样你就可以选择急切/延迟加载你的组件。

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

Would the following solution be of interest?

You can make a protected mapping to your components and access these from this public generic method.

This way you can choose to eager/lazy load your components.

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));
    }
}
姜生凉生 2024-11-25 07:10:53

鉴于此:

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; }
}

据我所知,您无法获取不属于实体的内容。因此,从您的示例来看,不可能从 Article 实体中获取元。

因此,如果你想获取一篇文章的其他信息,你只需要将 Article 加入其中,然后将完整的数据投影到你的 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 开始,然后获取 Article;在查询时,这将立即加入文章,即没有延迟加载:

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%'

要保持一篇文章只有一个元,请在元的引用上放置一个唯一:

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

Given this:

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

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

Resulting query:

select *
from [Article] article0_, [Meta] meta1_ 
where meta1_.ArticleId = article0_.ArticleId 
    and meta1_.Keywords like '%Some Word%'

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

Resulting query:

select *
from [Meta] meta0_ 
left outer join [Article] article1_ on meta0_.ArticleId = article1_.ArticleId 
where meta0_.Keywords like '%Some Word%'

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');
×纯※雪 2024-11-25 07:10:53

在 NHibernate 映射文件中,您可以指定获取类型。一对一 xml 的规范位于 NHibernate文档。请注意,数字 5 有一个“加入”和“选择”选项,并且默认为“选择”。

In your NHibernate mapping file, you can specify the fetch type. The spec for the one-to-one xml is located in the NHibernate Documentation. Notice that number 5 has an option of Join and Select and it defaults to select.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文