ここでリリックに同意する必要があります。.Net 用語では、データにオブジェクトを使用し、LINQ を使用してそれらのコレクションをクエリすることは、豊富なクエリ言語を指先で使用しながら、求めていることを実行する最速の方法の 1 つでなければなりません。
コレクションのサイズが心配で、すべての情報をメモリに保持できる場合は、Memcachedなどのプロジェクトを参考にしてください。
アップデート
Linq を条件オブジェクトと共に使用して製品のリストを照会する例を作成しました (ただし、Linq から Sql へのデータテーブルは簡単に作成できます)。
まず製品クラスの例:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Linq_Question
{
public class Product
{
public enum Categories
{
CatOne,
CatTwo,
CatThree
}
public int Id { get; set; }
public string Name { get; set; }
public Categories Category { get; set; }
public decimal Price { get; set; }
}
}
Product Criteria クラスの例
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Linq_Question
{
public class ProductCriteria
{
public Product.Categories? WhereCategoryIs { get; set; }
public decimal? WherePriceIsGreaterThan { get; set; }
public decimal? WherePriceIsLessThan { get; set; }
public string WhereNameContains { get; set; }
public ProductCriteria()
{
}
}
}
リポジトリの例 - リストの使用
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
namespace Linq_Question
{
public class ProductRepository
{
private List<Product> products;
public ProductRepository()
{
products = new List<Product>();
products.Add(new Product() { Category = Product.Categories.CatOne, Id = 1, Name = "Product 1", Price = 100 });
products.Add(new Product() { Category = Product.Categories.CatTwo, Id = 2, Name = "Product 2", Price = 120 });
products.Add(new Product() { Category = Product.Categories.CatThree, Id = 3, Name = "Product 3", Price = 300 });
products.Add(new Product() { Category = Product.Categories.CatOne, Id = 4, Name = "Product 4", Price = 400 });
products.Add(new Product() { Category = Product.Categories.CatTwo, Id = 5, Name = "Product 5", Price = 500 });
products.Add(new Product() { Category = Product.Categories.CatThree, Id = 6, Name = "Product 6", Price = 600 });
}
public IEnumerable<Product> Retrieve(ProductCriteria criteria)
{
return this.products.Where(FilterProducts(criteria));
}
private Func<Product, bool> FilterProducts(ProductCriteria criteria)
{
Expression<Func<Product, bool>> predicate = PredicateBuilder.True<Product>();
List<IProductFilter> filters = new List<IProductFilter>();
filters.Add(new PriceIsGreaterThanFilter());
filters.Add(new CategoryFilter());
foreach (var item in filters)
{
if (item.IsValidFilter(criteria))
{
predicate = predicate.And(item.ApplyFilter(criteria));
}
}
return predicate.Compile();
}
}
}
FilterProducts メソッドでは、フィルターのリストがループされ、現在の基準オブジェクトが与えられた場合に有効なフィルターであるかどうかがチェックされ、必要に応じて適用されることに注意してください。
IProductFilter インターフェイスといくつかのサンプル フィルターを次に示します。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
namespace Linq_Question
{
public interface IProductFilter
{
bool IsValidFilter(ProductCriteria criteria);
Expression<Func<Product, bool>> ApplyFilter(ProductCriteria criteria);
}
public class CategoryFilter : IProductFilter
{
public bool IsValidFilter(ProductCriteria criteria)
{
return (criteria.WhereCategoryIs.HasValue);
}
public Expression<Func<Product, bool>> ApplyFilter(ProductCriteria criteria)
{
return (p => p.Category == criteria.WhereCategoryIs.GetValueOrDefault());
}
}
public class PriceIsGreaterThanFilter : IProductFilter
{
public bool IsValidFilter(ProductCriteria criteria)
{
return (criteria.WherePriceIsGreaterThan.HasValue);
}
public Expression<Func<Product, bool>> ApplyFilter(ProductCriteria criteria)
{
return (p => p.Price > criteria.WherePriceIsGreaterThan.GetValueOrDefault());
}
}
}
PredicateBuilder クラスが必要になることに注意してください - 見つかりましたhttp://www.albahari.com/nutshell/predicatebuilder.aspx
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Collections.Generic;
namespace Linq_Question
{
public static class PredicateBuilder
{
public static Expression<Func<T, bool>> True<T>() { return f => true; }
public static Expression<Func<T, bool>> False<T>() { return f => false; }
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2)
{
var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
return Expression.Lambda<Func<T, bool>>
(Expression.OrElse(expr1.Body, invokedExpr), expr1.Parameters);
}
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2)
{
var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
return Expression.Lambda<Func<T, bool>>
(Expression.AndAlso(expr1.Body, invokedExpr), expr1.Parameters);
}
}
}
最後に、アイデアの動作を示す小さなコンソール アプリを次に示します。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Linq_Question
{
class Program
{
static void Main(string[] args)
{
ProductRepository repo = new ProductRepository();
Console.WriteLine("Items over 100");
foreach (var item in repo.Retrieve(new ProductCriteria() { WherePriceIsGreaterThan = 100 }))
{
Console.WriteLine(string.Format("Name {0}, Category {1}, Price {2}", item.Name, item.Category, item.Price));
}
Console.WriteLine("Items with a Category of Two");
foreach (var item in repo.Retrieve(new ProductCriteria() { WhereCategoryIs = Product.Categories.CatTwo }))
{
Console.WriteLine(string.Format("Name {0}, Category {1}, Price {2}", item.Name, item.Category, item.Price));
}
Console.Read();
}
}
}
このアイデアを拡張して複数のフィルターを追加し、IProductFilter から返された関数を式に AND または OR する必要があるかどうかを判断することもできます。
フィルタはリポジトリに挿入できるため、実行時に簡単に変更できます。
これがあなたにいくつかのアイデアを与えることを願っています。