c# - 在运行时映射一对一关系

标签 c# nhibernate linq-to-nhibernate

我正在尝试升级一个旧的 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 方法,以便它进行内部连接以获取元数据。这个概念看起来很简单,但我不知道从哪里开始。非常感谢您的帮助。

谢谢

最佳答案

鉴于此:

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 实体中获取 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开始,然后获取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%'

要让一篇文章只有一个 Meta,请在 Meta 的引用上放置一个 Unique:

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

关于c# - 在运行时映射一对一关系,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6581589/

相关文章:

c# - DTO 和 Entity 是否都应该有输入验证

linq - NHibernate Linq - 重复记录

c# - NHibernate Linq Query Where(x => x is Base Class) 没有得到派生对象

c# - 在C#.net 4中读取/写入字节数组

c# - 如何使用 BackgroundWorker 显示/隐藏 WPF UI 元素?

oracle - 如何使用 NHibernate 以编程方式调用 Oracle 存储过程?

c# - 如何在不进行大量重写的情况下在现有的 asp.net-mvc 站点上添加新路由?

nhibernate - LINQ to NHibernate 存在于何处

c# - 我如何遍历特定表单的所有打开实例?

c# - Web API OData : How do you $expand on a single entity?