web-dev-qa-db-fra.com

Requête de sélection LINQ avec type anonyme et type défini par l'utilisateur

La classe anonyme a des propriétés en lecture seule en c #. Ce qui est souvent utilisé pour déclarer dans linq select query pour obtenir des valeurs particulières de la base de données. Dans mon code, j'ai la requête suivante. La chose qui m'a dérouté en sélectionnant un nouvel objet de classe anonyme en utilisant une nouvelle déclaration. J'avais une classe modèle de StudentClerkshipsLogModel. Lorsque j'utilise le nom du modèle, le résultat de la requête permet la modification.

var query = (from entity in _tblStudentClerkshipsLog.GetQueryable()
             where entity.StudentID == intStudentID                             
             select new StudentClerkshipsLogModel
             {
                 StudentClerkshipID = entity.StudentClerkshipID,
                 StudentID = entity.StudentID,
                 ClerkshipID = entity.ClerkshipID,
             }).ToList();

Lorsque je n'ai pas mentionné le type après new dans select, je ne peux pas quitter. le compilateur génère une erreur. l'objet anonyme est en lecture seule.

var query = (from entity in _tblStudentClerkshipsLog.GetQueryable()
             where entity.StudentID == intStudentID                             
             select new 
             {
                 StudentClerkshipID = entity.StudentClerkshipID,
                 StudentID = entity.StudentID,
                 ClerkshipID = entity.ClerkshipID,
             }).ToList()

ma question est de savoir comment linq lie différemment les deux requêtes. Les deux requêtes ont une liaison dynamique ou la première est statique.

Merci

16
Muhammad Nasir

Si je vous comprends bien, vous vous demandez comment le fournisseur LINQ peut définir les propriétés d'un objet anonyme, car ce sont de véritables propriétés en lecture seule (il n'y a pas de private set, mais get uniquement)?

Lorsque vous appelez la méthode d'extension Select pour IQueryable<T>, il accepte un expression de type Expression<Func<T, TResult>. Si vous allez écrire un stub pour Select, vous pouvez regarder l'expression générée, en utilisant le débogueur:

public static class MyExtensions
{
    public static void MySelect<T, TResult>(this IQueryable<T> query, Expression<Func<T, TResult>> projection)
    {
        System.Diagnostics.Debug.WriteLine(projection);
    }
}

La différence réside dans la façon dont le compilateur génère des expressions lambda pour les types nommés et les types anonymes. Lorsque vous appelez Select pour le type nommé, l'expression ressemblera à ceci:

{_ => new Person() {Id = _.Id, Name = _.Name}}

En d'autres termes, un nouvel objet Person sera d'abord construit, puis les membres seront initialisés (expression MemberInit).

Mais lorsque vous appelez Select pour un type anonyme, l'expression sera construite en tant qu'appel de constructeur (New expression):

{_ => new <>f__AnonymousType0`2(a = _.Id, b = _.Name)}

Le fournisseur LINQ compile ces lambdas en délégués, lors de la matérialisation des résultats de la requête, et appelle finalement le constructeur pour le type anonyme.

11
Dennis

L'erreur que vous obtenez n'a vraiment rien à voir avec LINQ. Vous pouvez voir la même chose sans utiliser LINQ du tout:

var anonymous = new { Name = "Fred" };
anonymous.Name = "Joe"; // Error, as properties of anonymous types are read-only

Donc, si vous souhaitez modifier les objets récupérés par votre requête LINQ, vous ne devez pas utiliser de types anonymes. Mais les deux requêtes LINQ sont liées statiquement - les types anonymes sont toujours parfaitement connus au moment de la compilation et le compilateur leur applique des restrictions de type normales. Par exemple:

var anonymous = new { Name = "Fred" };
Console.WriteLine(anonymous.Foo); // Error: no property Foo
int bar = anonymous.Name; // Error: no conversion from string to int
17
Jon Skeet

J'ai trouvé la différence suivante avec le résultat de type anonyme d'un résultat LINQ.

  1. Le résultat n'est pas modifiable, par exemple si nous attribuons une valeur à une grille, elle sera en lecture seule.

  2. Problème avec la portée d'un objet anonyme.Nous ne pouvons pas passer le type à une autre méthode. définir un paramètre de type var; var doit toujours être suivi d'une expression d'initialisation.

Si vous avez besoin de résultats uniquement dans le contexte actuel à des fins de lecture seule, utilisez une requête anonyme. Si vous avez besoin d'un résultat dans une autre fonction, vous devez définir le type d'objet. le type d'objet après new sera créé avec les propriétés que vous voulez obtenir du résultat définissez ensuite entre accolades {}. Il n'est pas nécessaire d'initialiser toutes les valeurs de la classe de modèle.

2
Muhammad Nasir