Convertir type anonyme à nouveau C# 7 tuple de type
La nouvelle version de C# est là, avec la nouvelle fonctionnalité très utile Tuple Types:
public IQueryable<T> Query<T>();
public (int id, string name) GetSomeInfo() {
var obj = Query<SomeType>()
.Select(o => new {
id = o.Id,
name = o.Name,
})
.First();
return (id: obj.id, name: obj.name);
}
Est-il un moyen de convertir mon anonyme de type object obj pour le tuple que je veux revenir sans cartographie de la propriété par propriété (en supposant que les noms des propriétés de match)?
Le contexte est dans un ORM, mon SomeType objet a beaucoup d'autres propriétés, et il est mappé à une table avec beaucoup de colonnes. Je veux faire une requête qui apporte juste l'ID et le NOM, j'ai donc besoin de convertir le type anonyme dans un tuple, ou j'ai besoin d'un ORM Linq Fournisseur de savoir comment comprendre un n-uplet et mettre les propriétés liées colonnes dans l'instruction SQL select.
- pourquoi ne pas changer votre
Select()
pour créer un tuple instances plutôt que des instances d'un type anonyme? - êtes-vous certain que la volonté de traduire dans linq to entities? Il n'est pas explicitement un objectif EF cas ici, mais il serait bon de le préciser.
- Je pense que vous pouvez juste faire
return (obj.id, obj.name);
puisque vous avez les noms dans la signature de la fonction, mais je n'ai pas le C# 7 droit maintenant à le tester. - EF est discutable, les OP du code est de retour
(int id, string name)
. - Attendez, vous êtes sûr de votre classe anonyme est
new { id => o.Id, name => o.Name }
et pasnew { id = o.Id, name = o.Name }
- comment est-EF discutable? L'OP du code pourrait certainement revenir un n-uplet d'après la cartographie des résultats d'une requête.
- EF n'est jamais discutable lorsque l'on parle de requêtes Linq comme il se comporte tout à fait différemment de Linq to Objects.
obj
contient une instance d'un type anonyme; l'OP veut convertir dans un tuple.- et il y a une grande différence entre la cartographie d'un tuple DANS la sélection de l'expression et de la cartographie après que la requête a été résolu avec
.First()
. Si c'est une Linq to Sql expression, il va probablement échouer. - à l'exception de l'OP, la question n'est pas à propos d'une requête LINQ, c'est à propos de anonyme de type -> n-uplet. LINQ est hors de l'image.
- Vous avez dit de le faire dans le
Select
, la dernière fois que j'ai vérifié, c'est la partie de Linq. - peut-être l'OP devrait modifier la question de supprimer la spéculation? Mon commentaire (essentiellement) demande d'éclaircissements pour laquelle les OP pourraient modifier à-dire "non, je suis en utilisant EF."
- Que je peux accepter.
- Je veux savoir comment le faire dans ORM Linq mappé requêtes, je vais mettre à jour la question. Merci à tous.
Vous devez vous connecter pour publier un commentaire.
La réponse courte est non, dans la forme actuelle de C#7 il n'est pas dans le cadre de manière à atteindre vos objectifs mot à mot, puisque vous voulez accomplir:
Parce que
Query<SomeType>
expose uneIQueryable
, toute sorte de projection doit être effectuée à une arborescence d'expression.Select(x => new {})
.Il y a un ouvrir roslyn problème pour l'ajout de ce soutien, mais il n'existe pas encore.
Suite, jusqu'à ce que ce soutien est ajouté, vous pouvez le connecter manuellement à partir d'un type anonyme à un n-uplet, ou le retour de la totalité de l'enregistrement et de la carte le résultat d'un tuple directement pour éviter les deux démarches, mais c'est évidemment inefficace.
Alors que cette restriction est actuellement cuit dans Linq-to-Entités en raison d'un manque de soutien et de l'incapacité à utiliser paramétrable constructeurs dans un
.Select()
de projection, les deux Linq-to-NHibernate et Linq-to-Sql permettre un hack dans le formulaire de création d'un nouveauSystem.Tuple
dans le.Select()
de projection, puis retour à un ValueTuple avec le .ToValueTuple() méthode d'extension:Depuis Que Le Système.N-uplet peut être mappé à une expression, vous pouvez retourner un sous-ensemble de données à partir de votre table et le cadre pour gérer la cartographie de votre C#7 n-uplet. Vous pouvez ensuite déconstruire les arguments avec toute convention de nommage à vous de choisir:
System.ValueTuple
au lieu deSystem.Tuple
si vous avez nommé votre tuples.Bien sûr, par la création de la n-uplet de votre expression LINQ:
Selon pour une autre réponse concernant les pré-C# 7 tuples, vous pouvez utiliser
AsEnumerable()
pour éviter EF de mélanger les choses. (Je n'ai pas beaucoup d'expérience avec EF, mais cela devrait le faire:)CS8143 An expression tree may not contain a tuple literal.
Query<SomeType>
est plutôt trompeur.new {A = ..., B = ..., ...};
qui peut être converti en(A, B, ...)
? Je pense que la réponse à que question aurait à utiliser la réflexion (ce qui serait désordonné et sans doute pas vraiment la peine l'effort.)obj
pour le tuple que je veux revenir sans cartographie de la propriété par propriété (en supposant que les noms des propriétés de match)?" L'OP n'a probablement pas savoir que la réponse à que question (si, en effet, c'est la question) exigent de la réflexion..Select()
ne peut déconstruire un ValueTuple et l'outil en ligne est mis à la compilation.Id
, ou pas de la création de la anonyme de type..Select()
. Il n'est pas compatible d'un exemple.Query<SomeType>()
et nous ne savons pas encore. Si c'estIEnumerable<SomeType>
alors ce sera compiler, car aucune expression arbres sont nécessaires. Si c'estIQueryable<SomeType>
alors oui, il ne pourra pas compiler.First()
en face de laAsEnumerable()
. @DavidL.First()
est une exécution immédiate de l'opérateur, pas un streaming de l'opérateur. Et oui, vous pouvez utiliser.First()
avant.AsEnumerable()
, mais qui irait à l'encontre du point de la projection d'un tuple dans.Select
et vous pourriez aussi bien manuellement la propagation de l'objet point. C'est pourquoi la distinction entre linq to objects et linq to sql est tellement important...il peut modifier considérablement l'efficacité de la réponse et dans ce cas, l'OP nous a laissé suspendu :(.ValueTuple.Create(...)
devrait fonctionner!SQL Server Profiler
.Tout n-uplet littéraux ne sont pas actuellement pris en charge dans des arbres d'expression, cela ne signifie pas la
ValueTuple
type ne l'est pas. Il suffit de créer explicitement.IQueryable
ne sais pas à propos deValueTuple
, comme EF6Note pour n'importe qui sur une version inférieure de .NET:
Si vous êtes sur une version inférieure de .NET que 4.7.2 ou .NET de Base, vous devriez utiliser le Gestionnaire de Package Nuget pour installer le Système.ValueTuple à votre projet.
Alors, voici un exemple de l'obtention d'un n-uplet d'un Linq to SQL de la requête:
Qui a fonctionné pour moi, cependant, après le check-in, j'ai eu un construire un échec...lisez la suite.
Pour encore plus de plaisir et de jeux, j'ai malheureusement eu une version antérieure de C# sur mon serveur de build pour une raison quelconque. Si je devais revenir en arrière, car il ne reconnaît pas le nouveau tuple format de sur la .sélectionnez(o => (. o.record1, o.record2)) ligne (plus précisément, qu'il serait un tuple à cause de la parenthèse autour de o'.record1 et de l'o.record2). Donc, j'ai dû revenir en arrière et type de récupérer un peu plus:
Cette méthode, vous pouvez nommer votre tuple élément dans une linq sélectionnez
IQueryable