-
-
Save aiwas/0820994fa9420b085a854c666dc32e55 to your computer and use it in GitHub Desktop.
OrderByWithString
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Linq; | |
using System.Linq.Expressions; | |
namespace Net.Elendia.Sample.Linq; | |
public static class LinqExtensions { | |
/// <summary> | |
/// ORDER BY 句文字列を使ってソートします。 | |
/// </summary> | |
/// <typeparam name="T"></typeparam> | |
/// <param name="source"></param> | |
/// <param name="orderByQuery">ORDER BY 句文字列</param> | |
/// <returns></returns> | |
/// <exception cref="ArgumentException"></exception> | |
/// <remarks> | |
/// <code>Hoge,Fuga DESC,Piyo,Puyo DESC</code> | |
/// のような文字列を受け取り、 | |
/// <code>OrderBy(x => x.Hoge).ThenByDescending(x => x.Fuga).ThenBy(x => x.Piyo).ThenByDescending(x => x.Puyo)</code> | |
/// のようなメソッド呼び出しに変換します。 | |
/// </remarks> | |
public static IQueryable<T> OrderByWithString<T>(this IQueryable<T> source, string orderByQuery) { | |
IQueryable<T> result = source; | |
// ORDER BY 句文字列を列ごとに分解 | |
var orderByList = orderByQuery.Split(',') | |
.Select(a => { | |
string[] pair = a.Trim().Split(' '); | |
string name = pair[0]; | |
bool isAsc = (pair.Length == 1) || (pair[1] != "DESC"); | |
return new { Name = name, IsAsc = isAsc }; | |
}) | |
.ToList(); | |
if (orderByList.Count == 0) { | |
throw new ArgumentException("無効な ORDER BY 句が指定されました。"); | |
} | |
var type = typeof(T); | |
var parameter = Expression.Parameter(type, "x"); | |
for (int i = 0; i < orderByList.Count; i++) { | |
// メソッド名を決定 | |
string methodName = ((i == 0), orderByList[i].IsAsc) switch { | |
(true, true) => "OrderBy", | |
(true, false) => "OrderByDescending", | |
(false, true) => "ThenBy", | |
(false, false) => "ThenByDescending", | |
}; | |
// ラムダ式を構築 | |
var propertyInfo = type.GetProperty(orderByList[i].Name) | |
?? throw new ArgumentException("無効な ORDER BY 句が指定されました。"); | |
var propertyAccess = Expression.MakeMemberAccess(parameter, propertyInfo); | |
var orderByExpression = Expression.Lambda(propertyAccess, parameter); | |
var resultExpression = Expression.Call( | |
typeof(Queryable), | |
methodName, | |
new[] { type, propertyInfo.PropertyType }, | |
result.Expression, | |
Expression.Quote(orderByExpression) | |
); | |
// 連結 | |
result = result.Provider.CreateQuery<T>(resultExpression); | |
} | |
return result; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment