2010-11-03 4 views
4

Très bien, je suis un nouveau venu chez Data Services et LINQ qui a désespérément besoin de conseils. En quelques jours, j'ai rencontré de nombreux obstacles inattendus et je suis coincé sur un maintenant. J'espère que ce ne sont que des frustrations typiques d'apprendre un nouvel outil.Comment consommer les opérations de service de données WCF dans l'application client .NET?

J'ai un service de données WCF pour fournir des données à partir d'une table de base de données Sql Server de coordonnées Gps. En particulier, j'ai une méthode d'opération de service qui vous permet de spécifier une précision décimale et une plage de latitude/longitude pour produire une représentation plus générale des données.

Dans un navigateur Web, il semble fonctionner comme prévu. Toutefois, lorsque j'essaie d'appeler l'opération depuis mon application client, la liste renvoyée au client diffère de la liste générée par le service.

Je vais utiliser des morceaux de mon code pour expliquer les détails:

d'exploitation des services de données:

// This is my service operation that I need to call from my client app (see below). 
    // It should return an IEnumerable<Gps> (Gps is one of my Entity Model 
    // types) list of distinct GPS rounded to the number of decimal positions 
    // specified and within the range specified. 
    [WebGet] 
    public IEnumerable<Gps> GetGpsView(int decimalPlaces, decimal minLatitude, decimal minLongitude, decimal maxLatitude, decimal maxLongitude) 
    { 
     // I must first return a list of anonymous-type objects 
     // because LINQ does not seem to allow me to construct my 
     // Gps object within the query (one of those other issues 
     // I had to tip-toe around). 
     var list = (from g in this.CurrentDataSource.Gps 
        where g.Latitude >= minLatitude && 
          g.Latitude <= maxLatitude && 
          g.Longitude >= minLongitude && 
          g.Longitude <= maxLongitude 
        select new 
        { 
         Id = 0, 
         Latitude = Math.Round(g.Latitude, decimalPlaces), 
         Longitude = Math.Round(g.Longitude, decimalPlaces) 
        }).Distinct().ToList(); 

     // Now that I have my results, I need to convert the items in the 
     // list to my Gps entity object. 
     IEnumerable<Gps> gpsList = list.ConvertAll<Gps>(item => new Gps 
          { 
           Id = item.Id, 
           Latitude = item.Latitude, 
           Longitude = item.Longitude 
          }); 

     return gpsList; 
    } 

Si je déboguer la méthode ci-dessus (en cours d'exécution sur le serveur virtuel de Visual Studio) lorsqu'il est appelé À partir de mon application cliente, gpsList semble contenir les données correctes juste avant de retourner au client. En utilisant mes paramètres de test, j'obtiens une liste de 200 objets Gps distincts dont les valeurs sont arrondies aux décimales que je spécifie.

Cependant, une fois que les résultats sont renvoyés à la méthode appelante dans mon application client, j'ai une liste d'objets de 200 Gps, mais ils ont tous la même valeur. Pour être précis, la valeur dupliquée est la dernière valeur de mon ensemble de résultats attendu. J'ai confirmé cela en appelant cette opération dans un navigateur Web et en visualisant les résultats.

Méthode Client:

// Partial class extension of code auto-generated by service reference. 
public partial class HsiSideBySideEntities 
{ 
    public List<Gps> GetGpsView(int decimalPlaces, decimal minLatitude, decimal minLongitude, decimal maxLatitude, decimal maxLongitude) 
    { 
     this.IgnoreMissingProperties = true; 

     // Format my relative URI string. 
     string uri = string.Format("/GetGpsView?decimalPlaces={0}&minLatitude={1}M&minLongitude={2}M&maxLatitude={3}M&maxLongitude={4}M", decimalPlaces, minLatitude, minLongitude, maxLatitude, maxLongitude); 

     // If I debug both client and service at the same time, when I step over this 
     // line, it does reach my data service - and as I mentioned above, on the 
     // service end it appears to generate the correct results. 
     List<Gps> gpsList = this.Execute<Gps>(new Uri(uri, UriKind.Relative)).ToList(); 

     // However, the results are returned to the client code, my list contains 
     // duplicates of the last expected record. 
     return gpsList; 
    } 
} 

J'ai essayé de retirer le « ToList() » partie de la ligne « Execute() », mais lorsque je tente de voir le jeu de résultats dans le débogueur, il montre une exception qui lit, "Seule une énumération est prise en charge par cet IEnumerable." Pour autant que je sache, mon code client est tout d'abord suspect.

Après tout, tous les autres tests montrent que mon opération de service de données produit les résultats souhaités. Dois-je faire quelque chose de différent pour obtenir la liste d'objets IEnumerable du service de données? Je comprends qu'il existe une option CreateQuery(), mais j'ai lu que Execute() est l'itinéraire le plus approprié pour ce scénario.

Répondre

1

Il est probablement à cause de cela:

select new 
{ 
    Id = 0, 
    Latitude = Math.Round(g.Latitude, decimalPlaces), 
    Longitude = Math.Round(g.Longitude, decimalPlaces) 
} 

Je suppose que la propriété Id de l'entité GPS est votre clé primaire. Dans votre exemple, vous définissez l'ID de chaque Gps renvoyé à zéro. Dans la bibliothèque cliente WCF Data Services, les entités avec la même clé primaire sont traitées comme la même instance à la fois pour des raisons de suivi des modifications et pour que les graphes d'objets se comportent comme dans un environnement orienté objet, tel que .NET.

Si, pour une raison quelconque, vous ne pouvez pas attribuer un Id unique aux entités GPS, envisagez d'utiliser un Guid pour la clé primaire.

+0

Merci pour la suggestion.Cela m'a vraiment traversé l'esprit, mais je me suis dit que si c'était le cas ma liste ne serait pas correcte après cette section de code juste avant d'être retournée. Mais je vais essayer et laisser tout le monde savoir comment ça se passe. –

+0

Vous êtes mon héros pour la journée! Plutôt que de changer la section de code que vous avez décrite, j'ai changé la partie qui le convertit des types anonymes en objets Gps. Avant cela, je déclare "long id = 0;" puis définissez "Id = id ++" dans la routine de conversion, en donnant à chaque élément une valeur Id unique. Merci encore! –

Questions connexes