Entity Framework Core では、式を使用したクエリを実行して DTO オブジェクトに変換できます。この機能は、提供されたモデル:
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() }; }
およびクエリ:
dbContext.Models.Where(m => SomeCriteria).Select(Model.AsDto).ToList();
で例示されるように、オブジェクトとすべての子コレクションに対してうまく機能します。ただし、次のような疑問が生じます。コレクションではない子エンティティに対してどのような動作を実現できるでしょうか?たとえば、Model クラスに次のプロパティが含まれている場合:
public AnotherChildModel AnotherChildModel { get; set; }
式に変換を追加できます:
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 } };
ただし、2 番目の子モデルが必要になるたびにこのコードを繰り返します。 DTO オブジェクトに変換されることは望ましくありません。単一のエンティティに .Select() を使用する代わりの方法はありますか?
いくつかのライブラリが、この問題に対する直感的な解決策を提供します。
1. LINQKit:
LINQKit では、ExpandableAttribute を使用して .Select() 操作を個々のエンティティに適用できます:
[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 } };
クエリは次のように記述できます:
dbContext.Models .Where(m => SomeCriteria).Select(m => Model.AsDto(m)) .AsExpandable() .ToList();
2. NeinLinq:
LINQKit と同様に、NeinLinq は 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 } };
クエリは次のように変更できます:
dbContext.Models .Where(m => SomeCriteria).Select(m => Model.AsDto(m)) .ToInjectable() .ToList();
3. DelegateDecompiler:
DelegateDecompiler は、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 } }
クエリは次のように単純化できます:
dbContext.Models .Where(m => SomeCriteria).Select(m => Model.AsDto(m)) .Decompile() .ToList();
これらの各ライブラリは目的を達成します。 EF Core の処理前に式ツリーを変更することで、コードを繰り返す必要がなくなります。さらに、3 つすべてで、それぞれの IQueryProvider を挿入するための呼び出しが必要です。
以上が子プロパティからカスタム DTO を選択するための EF Core コードは効率的に再利用できますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。