Entity Framework Core permet d'effectuer des requêtes à l'aide d'expressions à convertir en objets DTO. Cette fonctionnalité fonctionne bien pour l'objet et toutes les collections enfants, comme en témoigne le modèle fourni :
public class Model { public int ModelId { get; set; } public string ModelName { get; set; } public virtual ICollection<ChildModel> ChildModels { get; set; } // Other properties, collections, etc. public static Expression<Func<Model, ModelDto>> AsDto => model => new ModelDto { ModelId = model.ModelId, ModelName = model.ModelName, ChildModels = model.ChildModels.AsQueryable().Select(ChildModel.AsDto).ToList() }; }
Et la requête :
dbContext.Models.Where(m => SomeCriteria).Select(Model.AsDto).ToList();
Cependant, la question se pose : comment des similaires peuvent-ils le comportement peut-il être atteint pour une entité enfant qui n'est pas une collection ? Par exemple, si la classe Model inclut la propriété :
public AnotherChildModel AnotherChildModel { get; set; }
Une conversion peut être ajoutée à l'expression :
public static Expression<Func<Model, ModelDto>> AsDto => model => new ModelDto { ModelId = model.ModelId, ModelName = model.ModelName, ChildModels = model.ChildModels.AsQueryable().Select(ChildModel.AsDto).ToList(), AnotherChildModel = new AnotherChildModelDto { AnotherChildModelId = model.AnotherChildModelId } };
Mais répéter ce code à chaque fois que le deuxième modèle enfant doit être converti en objet DTO n'est pas souhaitable. Existe-t-il une alternative à l'utilisation de .Select() pour une seule entité ?
Plusieurs bibliothèques offrent une solution intuitive à ce problème :
1. LINQKit :
Avec LINQKit, l'opération .Select() peut être appliquée à des entités individuelles à l'aide de ExpandableAttribute :
[Expandable(nameof(AsDtoImpl))] public static ModelDto AsDto(Model model) { _asDtoImpl ??= AsDtoImpl() .Compile(); return _asDtoImpl(model); } private static Func<Model, ModelDto> _asDtoImpl; private static Expression<Func<Model, ModelDto>> AsDtoImpl => model => new ModelDto { ModelId = model.ModelId, ModelName = model.ModelName, ChildModels = model.ChildModels.AsQueryable().Select(ChildModel.AsDto).ToList(), AnotherChildModel = new AnotherChildModelDto { AnotherChildModelId = model.AnotherChildModelId } };
La requête peut ensuite être écrite comme :
dbContext.Models .Where(m => SomeCriteria).Select(m => Model.AsDto(m)) .AsExpandable() .ToList();
2. NeinLinq :
Semblable à LINQKit, NeinLinq utilise l'attribut InjectLambda :
[InjectLambda] public static ModelDto AsDto(Model model) { _asDto ??= AsDto() .Compile(); return _asDto(model); } private static Func<Model, ModelDto> _asDto; private static Expression<Func<Model, ModelDto>> AsDto => model => new ModelDto { ModelId = model.ModelId, ModelName = model.ModelName, ChildModels = model.ChildModels.AsQueryable().Select(ChildModel.AsDto).ToList(), AnotherChildModel = new AnotherChildModelDto { AnotherChildModelId = model.AnotherChildModelId } };
La requête peut être modifiée comme suit :
dbContext.Models .Where(m => SomeCriteria).Select(m => Model.AsDto(m)) .ToInjectable() .ToList();
3. DelegateDecompiler :
DelegateDecompiler propose une approche concise en utilisant l'attribut Computed :
[Computed] public static ModelDto AsDto(Model model) => new ModelDto { ModelId = model.ModelId, ModelName = model.ModelName, ChildModels = model.ChildModels.AsQueryable().Select(ChildModel.AsDto).ToList(), AnotherChildModel = new AnotherChildModelDto { AnotherChildModelId = model.AnotherChildModelId } }
La requête peut être simplifiée en :
dbContext.Models .Where(m => SomeCriteria).Select(m => Model.AsDto(m)) .Decompile() .ToList();
Chacune de ces bibliothèques atteint l'objectif en modifiant l'arborescence d'expression avant le traitement EF Core, évitant ainsi le besoin de code répété. De plus, tous les trois nécessitent un appel pour injecter leur IQueryProvider respectif.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!