2009-08-30 7 views
1

Appréciez si je peux obtenir de l'aide pour écrire un LINQ qui obtiendra TOUS LES CHAMPS du tableau A, et les champs pour lesquels le profil 1 a une valeur dans le tableau AB, montrer la valeur, sinon Si le profil 1 n'a pas d'entrée dans la table AB, affichez la valeur comme nulle.Comment écrire ce qui suit dans Linq ou Sql

Tableau A

AID Field 
----------- 
1  OneField 
2  TwoField 
3  ThreeField 

Tableau B

BID Value 
----------- 
1  OneValue 
2  TwoValue 
3  ThreeValue 

Tableau AB

ABID AID BID ProfileId 
------------------------- 
1  1  1 1 
2  2  3 1 

Je suis en train d'écrire un Linq (ou requête SQL) qui me montrer pour le profil id 1, toutes les valeurs de la table a, et pour celles qui s'appliquent, la valeur de la table b.

par exemple.

ProfileID AID  Field  BID  Value 
-------------------------------------------------------- 
1   1   OneField  1   OneValue 
1   2   TwoField  3   ThreeValue 
1   3   ThreeField NULL  NULL 

Comme vous pouvez le voir, le but est d'obtenir tous les champs de la table A, et les domaines pour lesquels le profil 1 a une entrée dans le tableau AB, montrer la valeur de la table B, sinon si le profil 1 n'a pas entrée dans la table AB, puis montrer comme nulle.

Si la solution l'exige, je suis heureux d'écrire cela en sql et de l'appeler via proc stocké.

Merci

Répondre

0

Je suis une solution LINQ travailler avec un auto-test complet contenu. Je n'ai ajouté aucun assertion à la fin mais la variable à la fin "queryResult" contiendra une liste avec le résultat que vous désirez. Je l'ai testé et vérifié que cela fonctionne.Voici le code:

Edit: En réponse à votre commentaire Voici l'exemple n ° 2

public class tablea 
    { 
     public int AID { get; set; } 
     public string Field { get; set; } 
    } 
    public class tableb 
    { 
     public int BID { get; set; } 
     public string Value { get; set; } 
    } 
    public class tableab 
    { 
     public int ProfileID { get; set; } 
     public int AID { get; set; } 
     public string Field { get; set; } 
     public int BID { get; set; } 
     public string Value { get; set; } 
    } 

    public class result 
    { 
     public int? profileid { get; set; } 
     public int? aid { get; set; } 
     public string field { get; set; } 
     public string bid { get; set; } 
     public string value { get; set; } 
    } 

    [Test] 
    public void TestQuery() 
    { 
     var tablea = new List<tablea>(); 
     var tableb = new List<tableb>(); 
     var tableab = new List<tableab>(); 

     tablea.Add(new tablea{AID = 1,Field = "OneField"}); 
     tablea.Add(new tablea{AID = 2,Field = "TwoField"}); 
     tablea.Add(new tablea{AID = 3,Field = "ThreeField"}); 

     tableb.Add(new tableb{BID = 1,Value = "OneValue"}); 
     tableb.Add(new tableb{BID = 2,Value = "TwoValue"}); 
     tableb.Add(new tableb{BID = 3,Value = "ThreeValue"}); 

     tableab.Add(new tableab{AID = 1,BID=1,ProfileID = 1}); 
     tableab.Add(new tableab{AID = 2,BID=3,ProfileID = 1}); 

     var profileId = 1; 

     var q1 = (from a in tablea 
        let bid = (from ab in tableab where ab.ProfileID == profileId && ab.AID == a.AID select ab.BID).FirstOrDefault() 
        let value = (from ab in tableab where ab.ProfileID == profileId && ab.AID == a.AID && ab.BID == bid select ab.Value).FirstOrDefault() 
       select new result 
          { 
           profileid = profileId, 
           aid = a.AID, 
           field = a.Field, 
           bid = (bid == 0 ? "null" : bid.ToString()), 
           value = value ?? "null" 
          }).ToList(); 

    } 
+0

Salut Roberto. Merci pour cela, ça marche plutôt bien dans le test unitaire. Cependant, par rapport aux entités linq2sql, DefaultIfEmpty échoue car les valeurs passées dans la valeur par défaut si elles sont vides ont des contraintes fk sur elles et j'obtiens l'exception "System.Data.Linq.ForeignKeyReferenceAlreadyHasValueException: Opération non valide en raison de l'état actuel de l'objet". Bummer. Je vais continuer à essayer et poster quand je trouve une solution. merci. –

+0

putain ... si proche. Malheureusement, je n'utilise pas LINQ to SQL, donc je ne connais pas ses limites. Malheureusement si vous renvoyez null pour DefaultIfEmpty alors le reste de la requête échouera parce qu'il essaye d'accéder aux propriétés sur cet objet retourné .... – 7wp

+0

Merci Roberto. Cela m'a orienté dans la bonne direction. Je continuerais d'essayer. marquer le vôtre comme la réponse acceptée pour sa rigueur. +1 pour faire un test complet autonome. –

0

Cela devrait fonctionner (non testé):

SELECT ProfileID, A.AID, Field, B.BID, Value 
FROM AB 
LEFT OUTER JOIN A ON AB.AID = A.AID 
LEFT OUTER JOIN B ON AB.BID = B.BID 
+0

N'a pas ramené la rangée 3. C'est là que je suis coincé. –

0

Puisque vous voulez toutes les lignes du tableau A, vous devez commencer par le tableau A:

SELECT AB.ProfileID, A.AID, A.Field, B.BID, B.Value 
FROM A 
LEFT OUTER JOIN AB ON AB.AID = A.AID 
LEFT OUTER JOIN B ON AB.BID = B.BID 
WHERE (AB.ProfileID = 1 OR AB.ProfileID IS NULL) 

Si vous commencez avec la table AB dans votre requête, vous n'aurez jamais que ce qui est dans la table AB - et la ligne 3 n'a pas d'entrée dans la table AB.

Marc

+0

Merci marc, mais ce n'est pas encore tout à fait là car si j'ai plus de 1 profil dans la table AB, et le profil 2 AID = 3, alors la jointure externe gauche sur B ne fonctionne pas. Profileid 1 renvoie 2 enregistrements et profileid 2 renvoie 3. Je pense qu'il manque l'enregistrement car ProfileID ne sera pas nul quand un autre profil utilise AID = 3. –

+0

l'un des principaux problèmes ici est que vous essayez de sélectionner sur le profileID, mais vous voulez sélectionner plus que ce qui est disponible dans la table de jointure "AB" - ce qui le rend vraiment difficile ...... –

+0

Pourriez-vous il suffit d'ajouter ** ALL ** lignes que vous voulez sélectionner, y compris leur ProfileID dans la table "AB" et laissez simplement la colonne "BID" vide pour ceux qui n'ont pas une entité "B" associée ?? De cette façon, vous pouvez sélectionner à partir de la table de jointure AB et utiliser la clause WHERE "ProfileID = x" –

0

[code] var result = d'un dans un rejoindre ab ab sur a.aid est égal à ab.aid en tmp1 rejoindre b en b sur b.id est égal à ab.bid en tmp2 de c dans tmp1.DefaultIfEmpty()/* ceci est d'obtenir les valeurs nulles */ de d dans tmp2.DefaultIfEmpty() sélectionner de nouveaux { c.ProfileID, a.AID, a.Field,
c.bid, d.Valeur }; [/ code]

0

Voir l'exemple ci-dessous:

var result = from a in a 
      join ab in ab on a.aid equals ab.aid into tmp1 
     join b in b on b.id equals ab.bid into tmp2 
     from c in tmp1.DefaultIfEmpty() /* this is to get the null values */ 
     from d in tmp2.DefaultIfEmpty() 
     select new 
     { 
     c.ProfileID, 
     a.AID, 
     a.Field, 
       c.bid, 
     d.Value 
     }; 
+0

Merci! Vous pouvez aussi * éditer * vos propres messages et les changer - maintenant que vous en avez ajouté un deuxième, pourquoi ne pas supprimer le premier avec l'extrait de code non formaté ..... –

+0

Marc merci de m'avoir aidé out mais j'ai peur que je ne vois pas un bouton de suppression – Edwards

+0

Salut Edwards, merci pour le poste. Pour une raison quelconque, Visual Studio n'aime pas la deuxième jointure suivant la ligne avec la première jointure. Est-ce que je manque quelque chose? –

0

La version SQL ressemble à ceci

select TableA.*, TableB.* 
from TableA 
    left outer join TableC on TableA.ID = Aid 
    left outer join TableB on TableB.id = Bid 
where 
    TableC.ProfileID = 1 
    or TableC.ProfileID is null 

La jointure externe vous assure d'obtenir des résultats de TableA même s'il n'y a aucun enregistrement correspondant de l'autre côté de la jointure. Vous devez par conséquent autoriser des valeurs nulles dans ProfileID.

Questions connexes