2011-07-05 4 views
3

NHibernate를 사용하기 위해 이전 CMS를 업그레이드하려고하고 있으며 원래 데이터베이스 구조를 많이 방해 할 수 없습니다. 다음은 문제의 원인이되는 비트입니다.런타임에서 일대일 관계 매핑

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

재산상의 난 다음 두 테이블을 말해봐 기사 클래스. 그러나 응용 프로그램에서 나는 관리자가 기사에 적용되는 구성 요소를 활성화/비활성화 할 수 있습니다. 또한 나는 그들이 기사 클래스를 건드리지 않고 자신의 구성 요소를 추가하는 응용 프로그램을 확장하고 싶습니다.

이유 때문에 내가 기사 클래스에 대한 속성을 추가 할 수 없습니다.

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 *를 기사 INNER 가입 메타 ON Articles.Id = 메타 FROM .ArticleId Where Meta.Keywords LIKE '% Some Word %'

Meta를 얻기 위해 내부 조인을 수행하도록 Component 메서드를 매핑 할 수 있습니까? 개념은 매우 단순 해 보이지만 어디서부터 시작해야할지 모른다. 나는 정말 도움을 주셔서 감사합니다.

감사합니다.

+0

"... 관리자가 구성 요소를 활성화/비활성화 할 수 있습니다 ..."라는게 무슨 뜻입니까? –

답변

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 엔터티에서 메타를 가져올 수 없습니다.

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

결과 쿼리 :

당신이 제의 기타 정보를 가져 오기하려면

그래서, 당신은 단지 다음 Linq에, 예에서 완전한 데이터 프로젝트, 그들에게 제에 가입해야

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

다른 접근법은 메타에서 시작하여 기사를 가져옵니다.

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

는 메타의 참조에 고유을 넣어 하나의 메타를 갖는 제를 유지하려면 :

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

결과 쿼리 : 쿼리, 이것이 바로 제에 가입되며, 더 게으른 로딩 즉 없습니다

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

답변 감사합니다. 두 번째 옵션은 나에게 강력한 타이핑을 제공하지만, 만약 다른 컴포넌트가 Meta2라고 말하면, 그것은 떨어진다. 나는 첫 번째 접근법에서 아이디어를 좋아한다. (linq 질의는 간단하고 추가 구성 요소에 조인을 추가 할 수있다.) 그러나 필자는 필자가 강하게 입력 할 뷰를위한 추가 모델을 만들어야하므로 이상적으로 좋아하는 것보다 조금 더 많은 작업이 필요합니다. 내가 기사를 말할 수있는 방법이 있다면 .Component (). 설명 (기사 클래스/매핑이 그에 따라 수정 될 수 있음을 주목하십시오) 그것은 좋을 것입니다. 그렇지 않다면 어쨌든 당신의 도움을 위해 환호하십시오. – nfplee

+0

멋진 아이디어가있다 : 누군가가 Linq-NH에서 실행 가능하다면, 이것은 충분하지 않을 것이다 : 투영에 별명이 필요함에 따라'Fetch (a => a.Component ())' 컴파일러에 의해), nitpick하기 위해, 이것은 API'Fetch (a => new {art = a, meta = a.Component ()})'가 될 것입니다. 그들이 그 생각을 수용 할 수 있다면 NHibernate로부터 누군가에게 이메일을 보내라. –

+0

알았습니다. 도움을 청합니다. – nfplee

0

당신의 NHibernate 매핑 파일에서 가져 오기 유형을 지정할 수 있습니다. one-to-one xml의 사양은 NHibernate Documentation에 있습니다. 숫자 5에는 Join 및 Select 옵션이 있으며 기본값은 select입니다.

+0

그게 어떻게 구성 요소 ()을 매핑하는 데 도움이됩니까? – nfplee

+0

xml은 테이블 간의 매핑 세부 정보를 결정합니다. 구성 요소 은 개체 유형에 불과합니다. Article Types 클래스에 Meta of Compontent 이라는 속성을 넣은 다음 구성 XML 내부에서 해당 속성과 meta (일대일로) 사이의 관계를 정의해야합니다. – Zoidberg

+0

여전히 혼란 스럽습니다. 예를 들어 좀 더 자세한 답변을 제공해 주시겠습니까? – nfplee

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

안녕하세요, 이것이 유망 해 보입니다. 하지만 구성 요소를 어떻게 매핑 할 지 잘 모르겠습니다. 제 추측으로는 데이터베이스에 어떤 구성 요소가 기사에 적용되는지 말할 테이블이 필요합니다. 이것에 대한 여러분의 생각을 알려주세요. 감사 – nfplee