2017-08-15 6 views
1

J'ai été aux prises avec le problème suivant sur Entity Framework code-first.EF-code d'abord - IQueryable ayant multiplication sur une propriété décimale spécifique

J'ai une classe d'entité avec un nombre décimal, et j'ai un paramètre décimal multiplicateur.

Je souhaite créer une requête (sans l'appeler), qui renvoie les entités, mais la propriété Bar doit être multipliée avec mon paramètre.

De côté codage:

public class Foo 
{ 
    public Guid Id { get; set; } 
    public Decimal Bar { get; set; } 
} 

// this simple stuff returns the entities after some filterings. 
Context.Set<Foo>().Where(x => querying on many props).ToList(); 

Cette méthode est similaire ce que je veux atteindre:

public IQueryable<Foo> GetFooQuery(.. Many properties used to the query .. , Decimal Multiplier) 
{ 
    var IQueryablePart = Context.Set<Foo>().Where(querying with the parameters); 

    /* ... and what to do here? ... */ 
    /* IQueryablePart = IQueryablePart.Select(x => new { 
      Bar = Bar * Multiplier <-- this is okay 
     }); */ 
    // but how to retrieve the other columns without listing them one by one, and how to return the data as IQueryable<Foo> ? 

    return IQueryablePart; 
} 

Je voudrais utiliser cette méthode de la manière suivante:

IQueryable<Foo> FullQuery = null; 

for(some loop, may be 10 or 1000 iterations, it depends) { 
    var Part = GetFooQuery(/* .. query params ..*/, 2); 

    if(MyFullQuery == null) 
     FullQuery = Part; 
    else 
     FullQuery.Union(Part); 
} 

// and in the end, do the db call once: 
var Result = FullQuery.ToList(); 

En SQL, je voudrais le gérer comme ceci:

SELECT 
    Id, 
    Bar * @MyValue as Bar, 
    # and all other columns 
FROM 
    Foo 
WHERE 
    (param queries 1) OR 
    (param queries 2) OR 
    --- 
    (param queries N) 

Ma question est: quelle est la façon de le faire via IQueryable et EF? Le plus important, je dois appeler le DB une seule fois. Je pense qu'il peut s'agir d'un peu de construction de requêtes, mais je ne suis pas encore familier avec cela, toute aide sera très appréciée.

+1

Si les deux 'bar' et' MyValue 'font partie de la même table (ie entité), alors la solution logique serait de le récupérer avec une propriété auto dans votre code à la place. – silkfire

+0

Malheureusement, ils ne le sont pas. Le multiplicateur est calculé par code. –

+0

D'où obtenez-vous @MyValue? – silkfire

Répondre

0

EF6 ne prend pas en charge la projection (select) dans une classe mappée en tant qu'entité. Par conséquent, la seule option que vous avez est de projeter vers une classe anonyme ou spéciale. Pour votre scénario, le plus facile que je vois est une classe comme ceci:

public class FooBar 
{ 
    public Foo Foo { get; set; } 
    public decimal Bar { get; set; } 
} 

Ensuite, la méthode de requête unique pourrait ressembler à ceci:

public IQueryable<FooBar> GetFooQuery(.. Many properties used to the query .. , decimal multiplier) 
{ 
    return Context.Set<Foo>() 
     .Where(querying with the parameters) 
     .Select(foo => new FooBar 
     { 
      Foo = foo, 
      Bar = foo.Bar * multiplier 
     }); 
} 

vous pouvez maintenant construire votre requête complète:

IQueryable<FooBar> fullQuery = null; 

for (some loop, may be 10 or 1000 iterations, it depends) 
{ 
    var subQuery = GetFooQuery(/* .. query params ..*/, 2); 

    fullQuery = fullQuery == null ? subquery : fullQuery.Union(subQuery); 
} 

Notez que si vous utilisez un multiplicateur différent (sinon toute la procédure n'a pas de sens), vous feriez mieux d'utiliser la méthode LINQ (qui se traduit par SQL UNION ALL) plutôt en Union (qui se traduit par SQL UNION).

Enfin, vous pouvez matérialiser le résultat comme Foo sequennce en exécutant la requête SQL finale unique, le passage à LINQ aux objets et convertir le FooBar à Foo comme ceci:

var result = fullQuery. 
    .AsEnumerable() // db query ends here 
    .Select(fooBar => 
    { 
     fooBar.Foo.Bar = fooBar.Bar; 
     return fooBar.Foo; 
    }) 
    .ToList(); 
+0

Le multiplicateur varie entre les itérations, donc mon but était de faire en sorte que la base de données calcule la multiplication à la place de "moi" dans le code après avoir extrait les données de la base de données. –

+0

Cette solution de classe de transfert fait le calcul dans la base de données, cependant, j'ai encore besoin de sélectionner les éléments après avoir appelé la requête complète, mais c'est plus élégant que de faire le post-calcul après tout usage de la méthode. travail supplémentaire "avec la conciliation des requêtes de toute façon. Merci pour la solution. –