Le type apparaît dans les deux structurellement incompatible initialisations au sein d'une seule requête LINQ to entities
Je suis en train de construire quelque chose comme conditionnelle des requêtes pour obtenir uniquement les données nécessaires à partir de la base de données.
Actuellement, j'ai la requête suivante (qui fonctionne correctement)
var eventData = dbContext.Event.Select(t => new
{
Address = true ? new AnonymousEventGetAddress
{
AddressLine1 = t.Address.AddressLine1,
CityName = t.Address.AddressCityName
} : new AnonymousEventGetAddress(),
});
Si je l'ai changer pour
var includeAddress = true; //this will normally be passed as param
var eventData = dbContext.Event.Select(t => new
{
Address = includeAddress ? new AnonymousEventGetAddress
{
AddressLine1 = t.Address.AddressLine1,
CityName = t.Address.AddressCityName
} : new AnonymousEventGetAddress(),
});
J'obtiens l'erreur suivante:
Type "AnonymousEventGetAddress" apparaît dans deux structurellement incompatible initialisations au sein d'une seule requête LINQ to entities.
Un type peut être initialisé à deux endroits dans la même requête, mais seulement si les mêmes propriétés sont définies dans les deux endroits, et ces propriétés sont définies dans le même ordre.
Ce que je fais mal ici (avec le true
ça fonctionne) et comment cela peut-il être fixé?
Je sais que la modification de la else
-partie à
new AnonymousEventGetAddress
{
AddressLine1 = null,
CityName = null
}
fonctionne. Mais si je change l'ordre des propriétés ensuite, cela échouera également.
La classe utilisée est définie suivantes:
public class AnonymousEventGetAddress : BaseAnonymousObject<AnonymousEventGetAddress>
{
public string AddressLine1 { get; set; }
public string CityName { get; set; }
}
alors que BaseAnonymousObject<AnonymousEventGetAddress>
est défini:
public abstract class BaseAnonymousObject<TAnonymous>
where TAnonymous : BaseAnonymousObject<TAnonymous>
{
//this is used in case I have to return a list instead of a single anonymous object
public static Expression<Func<IEnumerable<TAnonymous>>> Empty => () => new TAnonymous[]{}.AsEnumerable();
}
IQueryable
donc Expression
de Func
si ces seront compilées à LINQ, ils ne sont pas exécutés...Je sais que lors de l'exécution des données est nécessaire. Donc, je cherchais un moyen de ne sélectionner que ce qui est vraiment nécessaire, également à partir de la base de données pour conserver les performances de bon. D'autre part j'utilise
LINQKit
pour permettre l'utilisation de Expression<>
qui fonctionnent très bien lors du passage de true
.Créer deux
Select
expressions, donc vous le faites si includeAddress
ou choisir une autre si c'est le contraire. N'essayez pas et composé dans l'expression qu'elle va se faire traiter comme une expression...C'était juste un exemple simplifié. En cas j'ai les trois en option
include...
ce serait la fin dans 8 requêtes différentes pour chaque combinaison d'entre eux... Donc je suis encore à se demander quelle est la différence entre la réussite includeAdress
(échoue) et true
(de travail).
OriginalL'auteur KingKerosin | 2016-08-25
Vous devez vous connecter pour publier un commentaire.
Je ne sais pas pourquoi EF a une telle exigence, mais la chose importante est que l'obligation existe et nous devons le prendre en compte.
Le premier code fonctionne car
true
est un compiler constante de temps, de sorte que le compilateur est à régler au moment de la compilation, de se retrouver avec l'un des deux expressions (essentiellement de retirer l'opérateur ternaire). Alors que dans le second cas, c'est un variable, donc, l'expression de l'arbre contient l'expression d'origine et échoue au moment de l'exécution en raison susmentionnée EF exigence.Il y a un moment que je cherchais à résoudre ce type de problèmes (pour être honnête, principalement pour la dynamique
where
filtres) par la mise en œuvre d'une méthode personnalisée qui est d'essayer de résoudre le bool variables, ce qui fait au moment de l'exécution de quelque chose de similaire à ce que fait le compilateur dans le premier cas. Bien sûr, le code est expérimental et n'est pas testé, mais semble gérer correctement de tels scénarios, de sorte que vous pouvez lui donner un essai. L'utilisation est assez simple:Et ici est la méthode d'assistance utilisés:
Mince, quand j'ai écrit c'est expérimental, je ne voulais pas dire qu'il doit échouer immédiatement:) en Fait, j'ai testé votre scénario sur mon EF environnement de test et ça a fonctionné. Le problème est que mon aide le code de la méthode était différente de celle que j'ai posté dans les liens (permettez-moi de ne pas oublier de mettre à jour plus tard) et copier/coller ici. Maintenant, c'est jusqu'à ce jour. A côté de ça, j'espère que vous comprenez pourquoi le premier cas avec la constante de
true
les travaux, tandis que la variabletrue
ne le fait pas.Pas de problème. Permettra de tester votre nouveau code plus tard. Et oui. Je comprends maintenant pourquoi
true
est de travail. Merci pour les précisions sur ce point. Retrait de laelse
partie fait totalement sens et il n'y aura pas de double initialisation de la gauche qui provoque EF à l'écrasement.OriginalL'auteur Ivan Stoev
Vous pouvez mettre l'instruction conditionnelle dans chaque propriété de l'initialiseur.
IEnumerable
avec des objets vides à la place d'un videIEnumerable
. Et je ne comprends toujours pas le point pourquoi avectrue
il est au travail, mais avecincludeAddress
il ne l'est pas?OriginalL'auteur Maarten
À mon avis, j'essaie toujours de se tenir à l'écart de mettre quelque chose de plus compliqué alors la sélection de données dans
IQueryable
parce qu'ils sontExpression
, ce qui signifie qu'ils ne sont jamais exécutées - ils sont compilés.Je souhaite donc s'attaquer à ce problème, comme si (ce qui a un bel air de simplicité autour d'elle):
Créer un DTO pour le retour des données:
Alors je voudrais diviser votre logique autour de l'
includeAddress
La méthode
NoAddress
ou ce que vous voulez l'appeler, il va ressembler, mais avec pas deAddress
, et vous carte il.Vous pouvez ensuite choisir simplement:
Si vous
Select
ne ont beaucoup de logique, puis je envisager de déplacer dans une procédure stockée, d'où il sera plus facile à lire le SQL.Évidemment, c'est juste un guide, vous donne une idée sur la façon d'aborder le problème.
OriginalL'auteur Callum Linington
Dans certaines circonstances, il est simple solution de contournement pourrait être possible: faire le type apparaissent comme différents types. E. g. faire 2 sous-classes de la classe d'origine. Cette solution de contournement est bien sûr assez sale, mais le Linq exigence est artificielle par lui-même. Dans mon cas, cela a aidé.
OriginalL'auteur alehro
J'ai eu le même problème et trouvé la solution, pour ajouter .ToList() , avant le select-fonction :
OriginalL'auteur JorgenV