Support AutoMapper's ProjectTo in DataSourceLoader
まだ誰も着手していません。
評価
- 難易度
- 5/5
- 見積もり時間
- 1週間以上
- 初心者へのやさしさ
- 25/100
- issue の種類
- 機能追加
- 明瞭さ
- おおむね明確
- 活発さ
- 停滞
- 技術スタック
- csharp
調査の方向性
DataSourceLoader.Load エントリポイントから開始し、フィルタリング、ソート、グループ化、プロジェクションがどのように適用されるかを追跡します。そのフローを issue にある AutoMapper ProjectTo の回避策と比較します。DataSourceLoader の操作を DTO のプロジェクション前に実行でき、返される結果のメタデータを保持できれば完了です。
索引モデルが issue の本文から書いたものです。
説明
As described in https://www.devexpress.com/Support/Center/Question/Details/T758528/modify-the-datasourceloader-to-support-projection-as-part-of-the-original-query-operation and referenced threads - repeated below for simplicity
In a nutshell, the issue is this;
It is best practice in EF to return a DTO rather than the original object. Regardless of best practice, efficiency demands in so in my application as I have tables with large text fields that are not necessary for populating lists and would increase the size of the payload over 100x. I get the data for my lists using DataSourceLoader GET controllers, and I use filtering, sorting and grouping in the DataSourceLoader extensively. I ProjectTo to ensure that my payload from SQL to API, and my payload from API to client are efficient and contain no more data that is necessary.
At the moment, it is impossible to perform operations on the full set of object properties, but return only a subset using ProjectTo. Any property specified in the options e.g. a filter occurs after the ProjectTo, so the property is not available for filtering at that point in the SQL. As per the ticket, you cannot simply operate on the data after it is returned, as it breaks other elements of the returned set for more complex operations like grouping.
Also, a Select is not the answer as this requires far too much hard coding to move between types - this is what automapper and ProjectTo are for.
At the moment I have created a workaround that;
- Returns the DataSourceLoader result if a Select is specified (obviously no projection is required in this case)
- Programatically identifies the key of the original entity (e.g. User => UserId)
- Runs the DataSourceLoader without Projecting, but returning only the Id of the entity - at this point I have all of the IDs matching the original query - IDset
- Performs a simple where(x=>IDset.Contains(x=>[IDProperty])).ProjectTo()
This works, but it would be far better if the datasourceloader could be modified to append my projection so it occurs after the datasourceloader filtering / sorting / grouping. I can't see that this would require much modification.
My code below for anyone else with this issue.
var src = _context.Approval.Where(x =>
x.ProjectId == _userService.Project_ID &&
x.PublishDate != null &&
x.NewApprovalId == null).Include(x => x.ApprovalTo);
var result = _context.FilterAsDto<Approval, ApprovalListDto>(src, loadOptions);
public LoadResult FilterAsDto<T, TDto>(Func<T, bool> preFilter, DataSourceLoadOptions loadOptions) where T : class
{
var qryResult = DataSourceLoader.Load(Set<T>().Where(preFilter), loadOptions);
if (loadOptions.Select == null || loadOptions.Select.Count()==0) return FilterAsDto<T, TDto>(qryResult, loadOptions);
else return qryResult;
}
public LoadResult FilterAsDto<T, TDto>(IQueryable<T> sourceQuery, DataSourceLoadOptions loadOptions) where T : class
{
var qryResult = DataSourceLoader.Load(sourceQuery, loadOptions);
if (loadOptions.Select == null || loadOptions.Select.Count() == 0) return FilterAsDto<T, TDto>(qryResult, loadOptions);
else return qryResult;
}
private LoadResult FilterAsDto<T, TDto>(LoadResult loadedData, DataSourceLoadOptions loadOptions) where T : class
{
var pkey = Model.FindEntityType(typeof(T)).FindPrimaryKey().Properties.Select(n => n.Name).Single();
var pKeyExp = Expression.Parameter(typeof(T));
var pKeyProperty = Expression.PropertyOrField(pKeyExp, pkey);
var keySelector = Expression.Lambda<Func<T, int>>(pKeyProperty, pKeyExp).Compile();
if (loadedData.data is IEnumerable<Group>) return loadedData;
else
{
var OriginalSummary = loadedData.summary;
List<int> idList = loadedData.data.Cast<T>().Select(keySelector).ToList();
var pKeyExpDto = Expression.Parameter(typeof(TDto));
var pKeyPropertyDto = Expression.PropertyOrField(pKeyExpDto, pkey);
var method = idList.GetType().GetMethod("Contains");
var call = Expression.Call(Expression.Constant(idList), method, pKeyPropertyDto);
var lambda = Expression.Lambda<Func<TDto, bool>>(call, pKeyExpDto);
var defOptions = new DataSourceLoadOptionsBase();
defOptions.Sort = loadOptions.Sort;
defOptions.RequireTotalCount = loadOptions.RequireTotalCount;
var returnData= DataSourceLoader.Load(Set<T>().ProjectTo<TDto>(_mapper.ConfigurationProvider).Where(lambda), defOptions);
returnData.summary = OriginalSummary;
returnData.totalCount = loadedData.totalCount;
return returnData;
}
}
- 主要言語
- C#
- スター
- 165
- フォーク
- 140
- 平均マージ
- 1日 2時間
- マージ済み PR(30日)
- 4
コントリビューションガイド
このリポジトリのコントリビューションガイドは索引されていません
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
DevExpress/DevExtreme.AspNet.Data のほかの issue
-
難易度 1/5 1時間未満 初心者へのやさしさ 78/100
-
難易度 5/5 1週間以上 初心者へのやさしさ 25/100
DevExpress/DevExtreme.AspNet.Data#588 · コメント 3 件 ·
-
難易度 4/5 3〜5日 初心者へのやさしさ 35/100
-
Dependency Dashboard オープン
難易度 4/5 3〜5日 初心者へのやさしさ 15/100
-
ES6 support オープンenhancement
難易度 5/5 1週間以上 初心者へのやさしさ 25/100
DevExpress/DevExtreme.AspNet.Data の issue をすべて見る
似ている issue
-
type/automation type/tech-debt
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
-
bug
難易度 2/5 1〜3時間 初心者へのやさしさ 88/100
-
t/bug
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
-
ci-failure-cause test-failure
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
-
area:auth FE mvp P3
難易度 2/5 1〜3時間 初心者へのやさしさ 88/100
klasolsson81/jobbliggaren#1788 ·