2017-06-22 4 views
2

Je construis une application web avec .Net Core en utilisant web api, angular 2 et NHibernate. J'ai les tableaux ci-dessous dans ma base de données:NHibernate La requête pour les résultats de json est inattendue

Todo

ID 
Name 
Priority 

priorité

ID 
Name 

Et le mappage suivant pour ces tableaux:

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

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

    [ManyToOne] 
    public virtual Priority Priority { get; set; } 
} 

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

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

J'ai également les éléments suivants DTO que je veux créer une liste de et l'envoyer au client Dans json: Dans le cadre de cet exemple, j'en ai enlevé d'autres propriétés.

public class TodoDTO 
{ 
    public long ID { get; set; } 

    public string Name { get; set; } 

    public Priority Priority { get; set; } 
} 

Quand je lance la requête ci-dessous:

var session = SessionFactoryConfigurationBase.GetSessionFactory().GetCurrentSession(); 

var query = session.QueryOver<Todo>(); 

TodoDTO todoSummary = null; 

query.SelectList(list => list 
    .Select(t => t.ID).WithAlias(() => todoSummary.ID) 
    .Select(t => t.Name).WithAlias(() => todoSummary.Name) 
    .Select(t => t.Priority).WithAlias(() => todoSummary.Priority)) 
.TransformUsing(Transformers.AliasToBean<TodoDTO>()); 

le JSON résultant ne montre pas les ID et Name propriétés de Priority mais il affiche les éléments suivants:

[{ 
    "id":1, 
    "name":"TEST", 
    "priority": 
    { 
     "__interceptor": 
     { 
      "persistentClass":"Todo, ApplicationName, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", 
      "identifier":2, 
      "isUninitialized":true, 
      "unwrap":false, 
      "session":null, 
      "entityName": "Priority", 
      "isReadOnlySettingAvailable":false 
     } 
    } 
}] 

Pourquoi il ne montre pas les propriétés ID et Name mais la définition de classe à la place? Lorsque je crée une liste séparée à partir de la requête ci-dessus, j'obtiens le résultat auquel je m'attendais au premier poing, mais cela semble plutôt lourd.

--------------------- EDIT ------------------------ -

Comme demandé le code qui ne me donne le résultat que je pense:

public IList<Todo> GetTodos() 
{ 
     var session = SessionFactoryConfigurationBase.GetSessionFactory().GetCurrentSession(); 

    var query = session.QueryOver<Todo>() 
    .Fetch(t => t.Priority).Eager 
    .List<Todo>(); 

    if(!query.Any()) 
    { 
     return null; 
    } 

    var result = (
     from t in query 
     select new TodoDTO 
     { 
      ID = t.ID, 
      Name = t.Name, 
      Priority = t.Priority 
     } 
    ).ToList();   

    return result; 
} 

le résultat est le retour au client avec le code suivant:

public JsonResult GetTodos() 
{ 
    var todos = GetTodos(); 

    return new JsonResult(todos); 
} 
+0

Quelle ligne génère le JSON? Pouvez-vous nous montrer l'alternative que vous avez écrite qui a fonctionné? – mjwills

+1

Je ne pense pas que vous ayez «matérialisé» vos résultats en utilisant la méthode 'List()' sur la 'query' résultante. –

+0

@ David Osborne: Je suis tout à fait sûr que c'est le problème, mais je ne sais pas comment y remédier exactement. – Bunnynut

Répondre

1

Ceci est probablement une manière plus propre pour accomplir ce que vous voulez:

var todos = 
    session 
     .Query<Todo>() 
     .Fetch(t => t.Priority) 
     .Select(t => 
      new { 
       t.ID, 
       t.Name, 
       Priority = new { 
        t.Priority.Id, 
        t.Prioriry.Name} 
      }) 
     .ToList(); 

return new JsonResult(todos); 

J'ai omis le DTO pour démontrer que ce n'est pas strictement nécessaire. Toutefois, l'appel Select() peut être modifié pour créer un nouveau DTO à la place.

Je veux juste m'assurer que je le fais bien.

Quand il vient à QueryOver() et Query(), il n'y a pas de « droit chemin ». Je trouve Query() est souvent plus lisible et plus propre mais manque parfois le contrôle dont j'ai besoin. Je commence généralement avec Query() et 'escalate' à QueryOver() si je suis bloqué ou je ne suis pas heureux le SQL Query() génère.

1
query.SelectList(list => list 
    .Select(t => t.ID).WithAlias(() => todoSummary.ID) 
    .Select(t => t.Name).WithAlias(() => todoSummary.Name) 
    .Select(t => t.Priority).WithAlias(() => todoSummary.Priority)) 
.TransformUsing(Transformers.AliasToBean<TodoDTO>()); 

La cause probable de votre problème est que vous n'assignez pas le résultat de cette ligne de code à une variable.

[{ 
    "id":1, 
    "name":"TEST", 
    "priority": 
    { 
     "__interceptor": 
     { 
      "persistentClass":"Todo, ApplicationName, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", 
      "identifier":2, 
      "isUninitialized":true, 
      "unwrap":false, 
      "session":null, 
      "entityName": "Priority", 
      "isReadOnlySettingAvailable":false 
     } 
    } 
}] 

Le JSON ci-dessus que vous recevez est probablement parce que vous êtes en train de convertir la variable query à JSON plutôt que le résultat de l'appel SelectList.

+0

Ok, je peux comprendre cela, mais comment puis-je le faire correctement alors? – Bunnynut

+0

Selon l'article suivant, il n'est pas possible de remplir des entités à une propriété: http://www.andrewwhitaker.com/blog/2014/06/19/queryover-series-part-4-transforming/ – Bunnynut

+0

"Vous ne pouvez pas remplir des entités complètes (Par exemple, .Select (() => productReview.Product) .WithAlias ​​(() => result.Product)) "Dans le paragraphe précédant le dernier de la section AliasToBean – Bunnynut