私は今朝、( https://stackoverflow.com/a/1447926/195550 )によって答えられているように見える質問( Query my model on a range of values )を見ましたが、そこでの全体的な状況は、より一般化された解決。
Jon Skeet の回答を使用して、SQL 以外で生成された環境で文字列キーを処理する a を実装できることを望んでいましたが、文字列がGreaterThan、LessThan、GreaterThanOrEqual、LessThanOrEqual演算子をBetween
実装していないという事実が入り込むようです。これを行うために必要な式ツリーを構築できるLinqの方法。
メソッドを使用してクエリを実行するだけでこのタスクを達成できることはわかっています
CompareTo
が、式の優雅さが本当に気に入っていquery.Between(v=>v.StringKey, "abc", "hjk")
ます。System.Linq.Expression アセンブリを調べたところ、GreaterThan 操作などの「op_GreaterThan」という名前のメソッドを探していることがわかりましたが、わかりません
- 文字列に対してこれを実装できるかどうか (文字列に対して実際の '>' 演算子を拡張できないことを知っています)
- 正しいメソッド シグネチャを構築する方法。
次の例と、Between 拡張メソッドが文字列キーで機能しない場所を示すテストを作成しました。
文字列キーに対して実装できれば、非常にエレガントです。これを達成する方法について、誰か提案や洞察がありますか?
包含フラグが追加された、Jon Skeet の Between 演算子
public static class BetweenExtension
{
public static IQueryable<TSource> Between<TSource, TKey>(
this IQueryable<TSource> source,
Expression<Func<TSource, TKey>> keySelector,
TKey low,
TKey high,
bool inclusive = true) where TKey : IComparable<TKey>
{
var key = Expression.Invoke(keySelector, keySelector.Parameters.ToArray());
var lowerBound = (inclusive)
? Expression.GreaterThanOrEqual(key, Expression.Constant(low))
: Expression.GreaterThan(key, Expression.Constant(low));
var upperBound = (inclusive)
? Expression.LessThanOrEqual(key, Expression.Constant(high))
: Expression.LessThan(key, Expression.Constant(high));
var and = Expression.AndAlso(lowerBound, upperBound);
var lambda = Expression.Lambda<Func<TSource, bool>>(
and, keySelector.Parameters);
return source.Where(lambda);
}
}
「int」キーを使用した上記の動作テスト
[TestFixture]
public class BetweenIntTests
{
public class SampleEntityInt
{
public int SampleSearchKey { get; set; }
}
private IQueryable<SampleEntityInt> BuildSampleEntityInt(params int[] values)
{
return values.Select(
value =>
new SampleEntityInt() { SampleSearchKey = value }).AsQueryable();
}
[Test]
public void BetweenIntInclusive()
{
var sampleData = BuildSampleEntityInt(1, 3, 10, 11, 12, 15);
var query = sampleData.Between(s => s.SampleSearchKey, 3, 10);
Assert.AreEqual(2, query.Count());
}
[Test]
public void BetweenIntNotInclusive()
{
var sampleData = BuildSampleEntityInt(1, 3, 10, 11, 12, 15);
var query = sampleData.Between(s => s.SampleSearchKey, 2, 11, false);
Assert.AreEqual(2, query.Count());
}
}
「文字列」キーを使用した上記の非動作テスト
[TestFixture]
public class BetweenStringsTests
{
public class SampleEntityString
{
public string SampleSearchKey { get; set; }
}
private IQueryable<SampleEntityString> BuildSampleEntityString(params int[] values)
{
return values.Select(
value =>
new SampleEntityString() {SampleSearchKey = value.ToString() }).AsQueryable();
}
[Test]
public void BetweenStringInclusive()
{
var sampleData = BuildSampleEntityString(1, 3, 10, 11, 12, 15);
var query = sampleData.Between(s => s.SampleSearchKey, "3", "10");
Assert.AreEqual(2, query.Count());
}
[Test]
public void BetweenStringNotInclusive()
{
var sampleData = BuildSampleEntityString(1, 3, 10, 11, 12, 15);
var query = sampleData.Between(s => s.SampleSearchKey, "2", "11", false);
Assert.AreEqual(2, query.Count());
}
}