2010-11-06 6 views
3

J'ai essayé de travailler avec la méthode Join et GroupJoin. Le problème semble simple. Compte tenu TableA et TableB comme cartes de données tel que:Implémentation correcte Join/GroupJoin

class MyDataContext : DataContext 
{ 
    public Table<tblA> TableA; 
    public Table<tblB> TableB; 
} 

... J'utilise TableA comme ma table principale et que vous souhaitez rejoindre sur un champ, dans CustomerIDTableB pour récupérer [TableB].[LastName].

Cela ne devrait pas être difficile, sauf que j'ai de la difficulté à obtenir des résultats satisfaisants. La TableA a des enregistrements que je veux, indépendamment d'un CustomerID correspondant dans la TableB. On dirait une jointure gauche - donc, la lecture here, j'imité ce @tvanfosson suggéré:

// appropriately rewritten for my needs - so I thought... 
private static IQueryable GetRecordsByView1(IQueryable<tblA> source) 
{ 
    var records = source.GroupJoin(myContext.TableB, 
        info => info.CustomerID, 
        owner => owner.CustomerID, 
        (info, owner) => new 
        { 
         info.CustomerID, 
         Owner = owner.Select(o => o.LastName).DefaultIfEmpty(), 
         Store = info.Store, 
        }) 
        .Select(record => new 
        { 
         record.CustomerID, 
         record.Owner, 
         record.Store, 
        }); 

    return records; 
} 

source est dynamique, telle qu'une méthode crée une requête dynamique:

public static void QueryStores() 
{ 
    IQueryable<tblA> source = myContext.TableA; 

    if (criteriaA) 
     source = source.Where(// something); 

    if (criteriaB) 
     source = source.Where(// something); 

    // after processing criteria logic, determine type of view 
    switch (byView) 
    { 
     case View1: 
     { 
      source = GetRecordsByView1(source); 
      break; 
     } 

     //other case blocks 
    } 

    myGridView.DataSource = source; 
} 

Le problème: Je suis recevoir l'erreur suivante:

Could not format node 'OptionalValue' for execution as SQL.

Je crois qu'il est dans la ligne de code suivante:

Owner = owner.Select(o => o.LastName).DefaultIfEmpty() 

Qu'est-ce que je fais mal ici? Je dois écrire GroupJoin comme une méthode d'extension.

Répondre

2

Première ... @ Brian m'a mis sur la bonne voie. Voici la solution:

var records = source 
       .GroupJoin(myContext.TableB, 
       info => info.CustomerID, 
       owner => owner.CustomerID, 
       (info, owner) => new 
       { 
        info, 
        Owner = owner.Select(o => o.LastName).First() 
       }) 
       .Select(record => new 
       { 
        record.info.CustomerID, 
        record.Owner, 
        record.info.Store 
       }); 

Cela me donne les résultats exacts souhaités ...

-1

Découvrez cet exemple join externe gauche: http://msdn.microsoft.com/en-us/library/bb397895.aspx

L'échantillon représentatif:

var query = from person in people 
join pet in pets on person equals pet.Owner into gj 
from subpet in gj.DefaultIfEmpty() 
select new { person.FirstName, PetName = (subpet == null ? String.Empty : subpet.Name) } 

Vous pouvez joindre les résultats dans gj, puis utilisez DefaultIfEmpty pour créer la situation de jointure externe, et toujours obtenir la résultats que vous voulez.

Quelqu'un d'autre a une erreur similaire en utilisant DefaultIfEmpty ici: Max or Default? http://blog.appelgren.org/2008/05/15/linq-to-sql-aggregates-and-empty-results/

HTH.

+0

Le problème est que je dois écrire mon 'Join' comme méthode d'extension. Je ne peux pas écrire en tant que déclaration LINQ. – IAbstract

3

Vous avez raison: Owner = owner.Select(o => o.LastName).DefaultIfEmpty() est la ligne à l'origine de vos problèmes. La meilleure solution que je suis venu avec quelque chose comme ceci:

var records = source.GroupJoin(myContext.TableB, 
        info => info.CustomerID, 
        owner => owner.CustomerID, 
        (info, owner) => new { info, owner }).ToList(); 
records.Select(x => new 
        { 
         x.info.CustomerID, 
         Owner = x.owner.First() == null ? new string[] {} : x.owner.Select(o => o.LastName).ToArray(), 
         Store = x.info.Store, 
        }) 
        .Select(record => new 
        { 
         record.CustomerID, 
         record.Owner, 
         record.Store, 
        }); 

Il est certainement pas idéal (vous devez matérialiser le GroupJoin avec « ToList »), et il pourrait y avoir une meilleure solution, mais a travaillé pour moi. Vous devrez peut-être jouer un peu pour que cela fonctionne bien pour vous, mais j'espère que cela vous aidera sur votre chemin.

+0

Cela semble prometteur. J'ai vu où il semble qu'il n'y a pas de matérialisation des données - je commence à le comprendre.Après avoir supprimé 'DefaultIfEmpty()', la requête passe mais le résultat du propriétaire est vide. Je suis entré dans les résultats et le nom de famille du propriétaire est là, mais enterré. Donc je sais que je suis proche ... merci. – IAbstract

+0

+ 1 pour avoir mis ma réflexion sur la bonne voie. – IAbstract

Questions connexes