2010-12-21 2 views
0

J'espère que ce sera une question plutôt simple pour tous ceux qui sont bons à Linq. J'ai du mal à trouver la bonne expression Linq pour ce qui suit. Je suis capable de pirater quelque chose pour obtenir les résultats, mais je suis sûr qu'il y a une façon propre et simple à Linq de le faire, je ne suis pas encore assez bon à Linq ...Expression Linq pour une collection filtrée de collections?

J'ai une base de données accessible à travers Entity Framework. Il a un certain nombre de tâches. Chaque tâche a une collection de TimeSegments. Les TimeSegments ont des propriétés Date et Employee. Ce que je veux, c'est être en mesure d'obtenir les tâches pour un certain employé et un certain mois et les délais pour chaque tâche pour ce même mois et l'employé.

Encore une fois, les tâches n'ont pas en elles-mêmes d'informations de mois ou de date, mais elles le font par les TimeSegments associés à chaque tâche.

très simplifiée il semble un peu comme ceci:

public class Model //Simplified representation of the Entity Framework model 
    { 
     public List<Task> Tasks { get; set; } 
    } 

    public class Task 
    { 
     public int Id { get; set; } 
     public List<TimeSegment> TimeSegments { get; set; } 
     public Customer Customer { get; set; } 
    } 

    public class TimeSegment 
    { 
     public int Id { get; set; } 
     public string Date { get; set; } 
     public Employee Employee { get; set; } 
    } 

    public class Employee 
    { 
     public int Id { get; set; } 
     public string Name { get; set; } 
    } 

Alors, comment dois-je faire cela aussi simplement que possible avec LINQ? C'est à dire. tâches et timesegments associés pour un certain mois et un employé. Je voudrais aussi être en mesure de l'obtenir par le Client BTW ...

Répondre

2

C'est la chose la plus simple que je pourrait venir avec:

var tasksWithSegments = 
    from segment in model.TimeSegments 
    where segment.Date.Month == month 
    where segment.Employee.Id == employeeId 
    group segment by segment.Task into result 
    select new 
    { 
     Task = result.Key, 
     TimeSegments = result.ToArray() 
    }; 

S'il vous plaît noter que vous pourriez avoir à ajouter des propriétés à votre modèle, comme Model.TimeSegment et TimeSegment.Task.

L'astuce avec les requêtes LINQ est souvent de commencer à la bonne collection. Dans ce cas, le point de départ idéal est TimeSegments.

ps. Je ne sais pas si Date.Month == month fonctionnera réellement avec EF, mais je pense que ce sera le cas (avec EF 4.0).


Mise à jour:

Pourriez-vous montrer comment étendre cette requête et obtenir les tâches pour ainsi client particulier?

Je ne suis pas sûr de ce que vous voulez dire, mais vous pouvez par exemple faire un filtrage du interrogeable précédent comme ceci:

var tasksWithSegmentsForCustomers = 
    from taskWithSegments in tasksWithSegments 
    where taskWithSegments.Task.Customer.Id == customerId 
    select taskWithSegments; 

Puis-je obtenir le type de retour à une liste des tâches avec une liste de TimeSegments si j'ai ceci dans une méthode?

Encore une fois, pas sûr de ce que vous voulez exactement, mais si vous voulez deux listes distinctes sans rapport, vous pouvez le faire:

List<Task> tasks = (
    from taskWithSegments in tasksWithSegments 
    select taskWithSegments.Task).ToList(); 

List<TimeSegments> segments = (
    from taskWithSegments in tasksWithSegments 
    from segment in taskWithSegments.Segments 
    select segment).ToList(); 

Bien sûr, si c'est ce que vous avez besoin, que il pourrait être plus facile de réécrire la requête d'origine à quelque chose comme ceci:

List<TimeSegment> segments = (
    from segment in model.TimeSegments 
    where segment.Date.Month == month 
    where segment.Employee.Id == employeeId 
    select segment).ToList(); 

List<Task> allTasks = 
    segments.Select(s => s.Task).Distinct().ToList(); 

Une fois que vous avez le coup de l'écriture de requêtes LINQ, il n'y a aucun moyen que vous voulez revenir à l'écriture d'instructions SQL ou des déclarations foreach ancienne mode .

Pensez LINQ !!!

+0

Cela semble fonctionner. Je pensais dans ce sens, mais je me sentais mal de commencer avec TimeSegments, je voulais commencer par les tâches. Mais peut-être que je ne suis pas habitué à la façon dont vous devez penser aux requêtes Linq comme vous le faites remarquer. Merci, je vais essayer ça. Pourriez-vous montrer comment étendre cette requête et obtenir les tâches pour un client particulier (voir la classe Task qui a une propriété Customer)? – Anders

+0

Aussi: Puis-je obtenir le type de retour à une liste de tâches avec une liste de TimeSegments si je l'ai dans une méthode? J'ai essayé d'utiliser ToList(), mais le compilateur se plaint toujours que le type de retour ne correspond pas. Je veux retourner Liste ... – Anders

+0

@Anders: Voir ma question mise à jour. – Steven

1

Ce que je veux être en mesure d'obtenir les tâches pour un certain employé et un certain mois et les timesegments pour chaque tâche pour ce même mois et employé.

Cela permet de sélectionner les tâches d'une instance de modèle où la tâche a au moins un segment de temps qui dans le mois demandé à l'employé demandé (non testé):

Model model = new Model(); 
tasks = model.Tasks.Where(t => t.TimeSegments.Any(ts => ts.Employee.Id = requestedId && Convert.ToDate(ts.Date).Month == requestedMonth)); 
+0

+1 - Battez-moi. – RPM1984

+0

Ok, mais cela ne sélectionnera que les tâches qui contiennent ces timesegments, puis sélectionnez ces tâches, non? Cela signifie que les tâches sélectionnées dans le résultat contiendront tous les timesegments, même ceux qui n'ont pas répondu au test de l'expression Any ... Et je n'ai besoin que des tâches qui contiennent ces timesegments, et incluons seulement les timbres-tests testés. – Anders

+0

Ensuite, vous avez deux options: Maintenant que vous avez les tâches que vous voulez, vous pouvez simplement les parcourir et accéder à task.TimeSegments.Where (ts => ts.Employee.Id = requestedId) - OU - Ajouter une référence arrière à la Objet tâche (ou collection de tâches si plusieurs à plusieurs) de l'objet TimeSegment, puis commencez par TimeSegments. Il y a plusieurs façons de peler un chat, mais choisir une stratégie dépend vraiment de ce à quoi vous voulez que votre chat ressemble quand vous avez terminé. – Keith

Questions connexes