2017-05-24 14 views
2

나는 아마도 매우 간단한 문제가있다. 내 데이터베이스에서 나는 다음과 같은 테이블이 있습니다NHibernate는 QueryOver를 사용하여 관련된 자식 객체를 가진 객체의리스트를 선택한다.

tblOrder 
----------------- 
Id 
OrderStatusId 

tblOrderStatus 
----------------- 
Id 
Name 

을 그리고 난 내 프로젝트에서 다음 매핑을 만들었습니다 :

[Class(NameType = typeof(Order), Table = "tblOrder") 
public class Order { 
    [Id(-2, Name = "Id")] 
    [Generator(-1, Class = "native")] 
    public virtual long Id { get; set; } 

    [ManyToOne] 
    public virtual OrderStatus Status { get; set; } 
} 

[Class(NameType = typeof(OrderStatus), Table = "tblOrderStatus")] 
public class OrderStatus { 
    [Id(-2, Name = "Id")] 
    [Generator(-1, Class = "native")] 
    public virtual long Id { get; set; } 

    [Property] 
    public virtual string Name { get; set; } 
} 

쿼리가 IList<OrderSummary>를 반환해야합니다. OrderSummary 클래스의 속성이 Status 인 경우 IdName 속성이있는 Status의 개체가 필요합니다. KeyValuePair 또는 유형이 OrderStatus (둘 중 가장 좋음과 어느 것이 든간에) 일 수 있습니다. 주문을 가져 오는 것은 문제가되지 않지만이 속성을 가진 객체로 OrderStatus을 추가하면 문제가있는 부분입니다. 또한 쿼리 결과를 JSON으로 클라이언트에 반환해야합니다.

OrderSummary은 다음과 같아야합니다

public class OrderSummary { 
    public long Id { get; set; } 
    public OrderStatus Status { get; set; } 
} 

를 내 첫 번째 버전 OrderSummary에서 OrderStatusIdOrderStatusName에 대해 별도의 속성을 가지고 있었다. 이 작동하지만 이러한 별도의 속성을 피하기 위해 노력하고있어. 나는 또한 SelectSubQuery과 함께 이것을 시도했지만 하위 쿼리에서 둘 이상의 필드를 반환하기 때문에 오류가 반환됩니다.

----------------------------------- 업데이트 ----------

var query = session.QueryOver<OrderStatus> 
    .Fetch(o => o.Status).Eager 
    .JoinAlias(o => o.Status,() => statusAlias, JoinType.LeftOuterJoin); 

문제는 다음과 같습니다 -------------------

프레디 Treboux의 조언에 따라 나는 다음과 같은 쿼리 결과 Eager를 사용하여 내 쿼리를 변경 , 데이터를 선택하는 것이 아니라 검색된 Status을 변환하여 OrderSummary.Status에 할당하는 방법을 찾았습니다. 나는 다음을 시도했다 :

OrderSummary orderAlias = null; 
query.SelectList(list => list 
    .Select(o => o.Id).WithAlias(() => orderAlias.Id) 
    .Select(() => statusAlias).WithAlias(() => orderAlias.Status) 
).TransformUsing(Transformer.AliasToBean<OrderSummary>()); 

-------------------------------- ANSWER ---- ------------------------------

마지막 편집에서 말한 것처럼 문제는 실제 선택은 OrderStatus이지만 클라이언트에 반환합니다. 그래서 나는 [JsonObject] 속성을 OrderStatus 클래스에 추가하는 것만 큼 간단하지 않았기 때문에 NHibernate에 대한 지식이 부족하다고 생각했습니다. 얼마나 어리석은 짓이야.

나는 다음에 내 쿼리를 변경 한 : 나는 현재이 불가능 것을 두려워

Order orderAlias = null; 
OrderSummary orderSummary = null; 
OrderStatus statusAlias = null; 
var query = session.QueryOver<Order>(() => orderAlias) 
    .JoinAlias(() => orderAlias.Status,() => statusAlias, JoinType.LeftOuterJoin); 

query = query 
    .Select(
     Projections.ProjectionList() 
      .Add(Projections.Property(() => orderAlias.Id).WithAlias(() => orderSummary.Id)) 
      .Add(Projections.Property(() => orderAlias.Status).WithAlias(() => orderSummary.Status) 
    ); 
Result = query.TransformUsing(Tranformers.AliasToBean<OrderSummary>()) 
    .List<OrderSummary>() 
    .ToList(); 
+0

여기를보세요 : https://stackoverflow.com/questions/29644236/use-nhibernate-aliastobean-transformer-launch-n1- 쿼리 –

+0

나는 귀하가 거기에 게시 한 링크는 거기에 코멘트에 포함 된 솔루션을 사용했습니다 : var query = session.QueryOver () .SelectList (list => ) .Select (Projections.Property ("OrderStatus" 결과는 괜찮은 것 같지만 json이 클라이언트에 보내지는 Order에는 OrderStatus 속성이 있지만 속성에는 실제 속성 값이 아니라 메타 데이터 만 포함되어 있습니다. – Bunnynut

+0

프록시 란 무엇입니까? 이 경우 상태 프로퍼티 –

답변

1

죄송합니다 이전에 예를 묻는 귀하의 의견을 보지 못했습니다. 이미 다른 응답에 대한 대안으로 주어졌다 있지만 내가 언급 한 접근 방식을 설명하는 몇 가지 코드를 떠날거야 그리고 그것이 (모든 변압기를 사용하지 않는) 이동하는 가장 쉬운 방법 생각 :

string GetOrderSummaries() 
{ 
    // First, you just query the orders and eager fetch the status. 
    // The eager fetch is just to avoid a Select N+1 when traversing the returned list. 
    // With that, we make sure we will execute only one query (it will be a join). 
    var query = session.QueryOver<Order>() 
         .Fetch(o => o.Status).Eager; 

    // This executes your query and creates a list of orders. 
    var orders = query.List(); 

    // We map these orders to DTOs, here I'm doing it manually. 
    // Ideally, have one DTO for Order (OrderSummary) and one for OrderStatus (OrderSummaryStatus). 
    // As mentioned by the other commenter, you can use (for example) AutoMapper to take care of this for you: 
    var orderSummaries = orders.Select(order => new OrderSummary 
    { 
     Id = order.Id, 
     Status = new OrderSummaryStatus 
     { 
     Id = order.Status.Id, 
     Name = order.Status.Name 
     } 
    }).ToList(); 

    // Yes, it is true that this implied that we not only materialized the entities, but then went over the list a second time. 
    // In most cases I bet this performance implication is negligible (I imagine serializing to Json will possibly be slower than that). 
    // And code is more terse and possibly more resilient. 

    // We serialize the DTOs to Json with, for example, Json.NET 
    var orderSummariesJson = JsonConvert.SerializeObject(orderSummaries); 
    return orderSummariesJson; 
} 

유용한 링크 :
AutoMapper : http://automapper.org/
Json.NET : http://www.newtonsoft.com/json

2

. 나는 Nhibernate 변압기가 중첩 된 복잡한 속성을 만들 수 없다고 생각한다. 당신은 당신의 엔티티에 수동으로 캐스팅 한 후 튜플의 목록을 반환 할 수 있습니다 : 당신이 성능에 대해 걱정하지 않는 경우에 많이 사용하면 주문 목록을 가져오고 OrderSummary로 변환하는 것이 가능

OrderStatus statusAlias = null;   

var tuples = Session.QueryOver<Order>() 
      .JoinQueryOver(x => x.Status,() => statusAlias) 
      .SelectList(list => list 
       .Select(x => x.Id) 
       .Select(x => statusAlias.Id) 
       .Select(x => statusAlias.Name)) 
      .List<object[]>(); 

var result = tuples.Select(Convert); 

private OrderSummary Convert(object[] item) { 
      return new OrderSummary 
      { 
       Id = (long)item[0], 
       OrderStatus = new OrderStatus { Id = (long)item[1], Name = (string)item[2] } 
      }; 
     } 

을 또한. 캐스팅 연산자를 정의하거나 AutoMapper 또는 ExpressMapper과 같은 도구를 사용하면됩니다.