Question

Je dois filtrer les éléments enfants d'une entité dans linq à l'aide d'une seule requête linq. Est-ce possible?

Supposons que j'ai deux tables liées. Verses et VerseTranslations. L'entité créée par LINQ to SQL est telle que j'ai un objet Verse qui contient un objet enfant qui est une collection de VerseTranslation.

Maintenant, si j'ai la requête linq suivante

var res = from v in dc.Verses
                  where v.id = 1
                  select v;

Je reçois une collection de vers dont l'identifiant est 1 et chaque objet de vers contient tous les objets enfants de VerseTranslations.

Ce que je veux aussi faire, c'est filtrer cette liste d'enfants de Verse Translations.

Jusqu'à présent, la seule façon dont j'ai pu arriver est d'utiliser un nouveau type anonyme ou autre. Comme suit

var res= from v in dc.Verses
                   select new myType
                   {
                       VerseId = v.VerseId,
                       VText = v.Text,
                       VerseTranslations = (from trans in v.VerseTranslations
                                               where languageId==trans.LanguageId
                                               select trans
                   };

Le code ci-dessus fonctionne, mais je devais déclarer une nouvelle classe pour cela. N'y a-t-il aucun moyen de le faire de telle manière que le filtrage sur la table enfant puisse être incorporé à la première requête linq de sorte qu'aucune nouvelle classe ne soit déclarée.

Cordialement, MAC

Était-ce utile?

La solution

Donc, je l’ai enfin fait fonctionner grâce aux indications données par Shiraz.

        DataLoadOptions options = new DataLoadOptions();
        options.AssociateWith<Verse>(item => item.VerseTranslation.Where(t => languageId.Contains(t.LanguageId)));

        dc.LoadOptions = options;

        var res = from s in dc.Verse
                   select s;

Cela ne nécessite pas de projection ni d’utilisation de nouvelles classes d’extension.

Merci à tous vos collaborateurs.

Autres conseils

Filtrage sur la collection incluse de l'objet,

var res = dc.Verses
            .Update(v => v.VerseTranslations 
                      =  v.VerseTranslations
                          .Where(n => n.LanguageId == languageId));

En utilisant la méthode d'extension " Mettre à jour " sur HookedOnLinq

public static class UpdateExtensions {

    public delegate void Func<TArg0>(TArg0 element);

    /// <summary>
    /// Executes an Update statement block on all elements in an IEnumerable<T> sequence.
    /// </summary>
    /// <typeparam name="TSource">The source element type.</typeparam>
    /// <param name="source">The source sequence.</param>
    /// <param name="update">The update statement to execute for each element.</param>
    /// <returns>The numer of records affected.</returns>
    public static int Update<TSource>(this IEnumerable<TSource> source, Func<TSource> update) {
        if (source == null) throw new ArgumentNullException("source");
        if (update == null) throw new ArgumentNullException("update");
        if (typeof(TSource).IsValueType) 
            throw new NotSupportedException("value type elements are not supported by update.");

        int count = 0;
        foreach(TSource element in source) {
            update(element);
            count++;
        }
        return count;
    }
}

S'il s'agit d'une base de données, vous pouvez exécuter votre première instruction.

Effectuez ensuite un chargement ou une inclusion de VerseTranslations avec une clause Where.

http://msdn.microsoft.com/en-us/library /bb896249.aspx

Avez-vous une relation dans votre modèle entre Verse et VerseTranslations. Dans ce cas, cela pourrait fonctionner:

var res= from v in 
dc.Verses.Include("VerseTranslations").Where(o => languageId==o.LanguageId)
select v;
  

N'y a-t-il aucun moyen de le faire dans un tel   manière telle que le filtrage sur le   table enfant peut être incorporé dans le   première requête linq afin qu'aucune nouvelle   les classes doivent être déclarées?

Techniquement, la réponse est non. Si vous essayez de renvoyer plus de données qu'un objet entité unique (Verse, VerseTranslation) ne peut en contenir, vous aurez besoin d'une sorte d'objet pour "projeter". dans. Cependant, vous pouvez contourner explicitement la déclaration de myType en utilisant un type anonyme:

var res = from v in dc.Verses
          select new
          {
              Verse = v,
              Translations = (from trans in v.VerseTranslations
                              where languageId==trans.LanguageId
                              select trans).ToList()
          };

var first = res.First();
Console.WriteLine("Verse {0} has {1} translation(s) in language {2}.",
    first.Verse.VerseId, first.Translations.Count, languageId);

Le compilateur générera pour vous une classe avec les propriétés Verse et Traductions correctement typées. Vous pouvez utiliser ces objets pour à peu près n'importe quoi tant que vous n'avez pas besoin de faire référence au type par nom (pour renvoyer à partir d'une méthode nommée, par exemple). Donc, bien que vous ne soyez pas techniquement "déclarant" un type, vous utilisez toujours un nouveau type qui sera généré selon vos spécifications.

En ce qui concerne l'utilisation d'une seule requête LINQ, tout dépend de la manière dont vous souhaitez structurer les données. Pour moi, il semble que votre requête initiale ait le plus de sens: associez chaque verset à une liste filtrée de traductions. Si vous prévoyez une seule traduction par langue, vous pouvez utiliser SingleOrDefault (ou FirstOrDefault ) pour aplatir votre sous-requête ou simplement utiliser un SelectMany similaire à ceci:

var res= from v in dc.Verses
         from t in v.VerseTranslations.DefaultIfEmpty()
         where t == null || languageId == t.LanguageId
         select new { Verse = v, Translation = t };

Si un vers comporte plusieurs traductions, une "ligne" sera renvoyée. pour chaque paire de vers / traduction. J'utilise DefaultIfEmpty () en tant que jointure à gauche pour être sûr d'obtenir tous les versets, même s'il leur manque une traduction.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top