2010-05-27 5 views
1

J'ai deux tables:Comment faire une jointure de table sur deux champs dans ma deuxième table?

  • Messages - Entre autres choses, a un to_id et un from_id terrain.
  • personnes - a un correspondant person_id

J'essaie de comprendre comment faire ce qui suit dans un seul LINQ requête:

Donnez-moi tous les messages qui ont été envoyés et à partir de la personne x (idself).

J'ai eu quelques fissures à ce sujet.

Pas tout à fait

MsgPeople = (from p in db.people 
      join m in db.messages on p.person_id equals m.from_id 
      where (m.from_id == idself || m.to_id == idself) 
      orderby p.name descending 
      select p).Distinct(); 

Cela fonctionne presque, sauf que je pense qu'il manque un cas:

"Les gens qui ont jamais reçu un message, envoyé pour me"

Comment cela fonctionne dans ma tête

Alors ce que je vraiment besoin est quelque chose comme:

join m in db.messages on (p.people_id equals m.from_id or p.people_id equals m.to_id) 

me fait un sous-ensemble des personnes que je suis après

Il semble que vous ne pouvez pas faire cela. Je l'ai essayé quelques autres options, comme faire deux jointures:

MsgPeople = (from p in db.people 
      join m in db.messages on p.person_id equals m.from_id 
      join m2 in db.messages on p.person_id equals m2.to_id 
      where (m2.from_id == idself || m.to_id == idself) 
      orderby p.name descending 
      select p).Distinct(); 

mais cela me donne un sous-ensemble des résultats dont j'ai besoin, je suppose que quelque chose à faire avec l'ordre les jointures sont résolues.

Ma compréhension de LINQ (et peut-être même de la théorie des bases de données) est embarrassante superficielle et j'ai hâte d'avoir un peu de lumière sur mon problème.

Répondre

2

Les gens qui ont envoyé des messages à lui-même ou les messages recus de soi.

from p in People 
where p.SentMessages.Any(m => m.to_id == idself) 
    || p.ReceivedMessages.Any(m => m.from_id == idself) 
select p; 

Si vos gens n'ont pas de ces propriétés Messages, create the associations.


Si vous voulez tirer des dents à la place ... voici la même requête sans associations.

IQueryable<int> sentQuery = 
    from sent in Messages 
    where sent.to_id = idself 
    select sent.from_id; 

IQueryable<int> receivedQuery = 
    from received in Messages 
    where received.from_id = idself 
    select received.to_id 

IQueryble<People> result = 
    from p in people 
    where System.Linq.Queryable.Concat(receivedQuery, sentQuery) 
    .Any(id => id == p.personId) 
    select p; 
+0

J'ai évité cela car cela pourrait causer des échecs, l'association ne peut être que sur un champ, donc disons que vous choisissez to_id, si la personne dans idself n'a pas envoyé un email il manquera en tant que SQL cela génère serait SELECT [t0]. [person_id] de [personnes] AS [t0] OÙ EXISTE ( SELECT NULL AS [EMPTY] de [messages] AS [t1] OÙ (([t1]. [to_id] = @ p0) OU ([t1]. [from_id] = @ p1)) AND ([t1]. [to_id] = [t0].[Person_id]) ) Je pense que – Pharabus

+0

J'ai manqué le fait qu'il existe plusieurs relations entre les gens et les messages. Fixé! –

+0

ouais cela fonctionne +1 de moi pour utiliser les relations :) aussi j'ai découvert que LINQPad nomme joliment les associations pour moi aussi! – Pharabus

1

peut-être qu'il me manque quelque chose mais il semble que vous n'avez pas besoin d'une jointure, vous dites "Donnez-moi tous les messages qui ont été envoyés à et de la personne x (idself)."Donc, si vous voulez juste les messages que vous pouvez travailler à partir juste qu'il table de message, comme l'identifiant (idself) est connu

var MsgPeople from p in AllMessages 
        where p.from_id == idself || p.to_id == idself 
        select p; 

ok, essayez ceci, vous devez vraiment une liste des ids pour les personnes qui vous ont envoyé des messages , et une liste de ceux qui de vous avez reçu des messages, vous pouvez choisir parmi les gens des personnes qui existent dans cette liste

var MsgPeople = from p in db.people 
         where (from m in db.messages 
           where m.from_id == selfid 
           select m.to_id).Union(
         from m in db.messages 
         where m.to_id == selfid 
         select m.from_id).Contains(p.person_id) 
         select p; 

une autre façon de faire, que je suis de SQL ingénierie inverse de notre DBA quand je posé la question

var MsgPeople = from p in Peoples 
    where p.Person_id != selfid && 
    (from m in Messages 
    where m.To_id == selfid select m.From_id).Union(
    from m in Messages 
    where m.From_id == selfid select m.To_id).Contains(p.Person_id) 
    select p; 
+0

Malheureusement, cela me donne juste des messages. Je suis après les gens qui ont envoyé des messages à et de moi. – RedBlueThing

+0

@Cannonade J'ai ajouté un peu plus de code basé sur votre commentaire, je pense que peut-être je peux améliorer cela en utilisant un syndicat, essayez ceci, en passant LINQPad est un très bon outil pour essayer ce genre de chose – Pharabus

+0

@Pharabus Merci mec ... Je vais essayer et vous dire comment je vais. – RedBlueThing

0

essayer peut-être un syndicat

select all the messages sent by user received by me 
union 
select all the messages received by user sent by me 
+0

Merci. Mais je cherche spécifiquement de l'aide avec la syntaxe de requête linq :) – RedBlueThing

Questions connexes