任意长度ORDER by使用NHibernate
本文关键字:使用 NHibernate by ORDER 任意长 | 更新日期: 2023-09-27 18:13:25
如果我使用PHP和MySQL做这个,它看起来会像这样(免责声明这段PHP代码不适合外部/面向web的使用,因为它很容易受到SQL注入):
<?php
function orderByColumns ($columns, $sql) {
if (0 < count($columns)) {
$column = array_shift($columns);
if (! stripos($sql, "ORDER BY")) {
$sql .= " ORDER BY";
}
$sql .= " {$column['name']} {$column['dir']}";
$sql .= 0 < count($columns) ? "," : "";
return orderByColumns($columns, $sql);
}
return $sql;
}
$columns = array(
array(
"name" => "foo",
"dir" => "ASC"
),
array(
"name" => "bar",
"dir" => "DESC"
)
);
$sql = "SELECT * FROM baz";
$sql = orderByColumns($columns, $sql); // And from here I could make my query
关键是$columns
是来自某个地方的用户的输入,并且它可以用于在不事先知道列表的情况下对列进行排序,并且是一种可重用的方法。
我正在寻找一种方法来做一些类似的使用c#,特别是NHibernate,但它似乎并没有真正工作。以下是我一直在c#中尝试的一些东西:
List<string> columns = new List<string>()
{
"Column1",
"Column2",
"Column3"
// And there could be more.
}
string column = columns.First();
fq = foo.Queryable.OrderBy(
i => i.GetType().GetProperty(column).GetValue(i, null)
);
foreach (string column in columns)
{
fq = fq.ThenBy(
i => i.GetType().GetProperty(column).GetValue(i, null)
);
}
而且,我看过一些StackOverflow的答案(好吧,不止几个),但他们似乎没有解决如何在我寻找的方式动态构建NHibernate查询。其中最有希望的是nHibernate中的Dynamic QueryOver,但我很难完全确定这是否在正确的方向上。
那么,问题是你在这里没有执行任何东西,所以nhibernate将尝试将其转换为SQL,这将抱怨,因为它不知道GetType()
方法。
您必须构建自己的Expression实例,并且没有很好的方法可以动态地做到这一点,尽管可以做到,但仍然不是很有趣。
我认为它会更容易做一个字典的lambda表达式和列
var lookup = new Dictionary<string, Expression<Func<T, object>>> {
{ "ColumnA", x => x.ColumnA },
{ "ColumnB", x => x.ColumnB }
};
foreach (string column in columns) {
fq = fq.ThenBy(lookup[column]);
}
即使这样,如果它抱怨Expression<Func<T,object>>
我对这个问题很感兴趣,想试着让@DarrenKopp的回答变得通用。我的代码比我预期的要冗长,但我相信它确实有效。我测试了Linq to Objects,所以nHibernate的Linq提供程序是未测试的。
代码在这里。
你可以像这样调用它…
var sortedItems = items.OrderBy(
new OrderByKeyInfo ("MyPropertyA", OrderByDirection.Descending),
new OrderByKeyInfo ("MyPropertyB", OrderByDirection.Ascending),
new OrderByKeyInfo ("MyPropertyC", OrderByDirection.Ascending));
下面是关于动态排序条件的一个快速概念证明。你可能会发现,避免通过NHibernate访问数据库可能会更好,因为如果初始排序包含8条记录,可能会让用户感到困惑,但是再次排序数据返回9,因为在中间添加了一条新记录,现在显示为我们已经回到了数据库,而不仅仅是重新排序内存中的集合-我不确定这是否/如何映射到NHibernate。
对于控制台应用程序来说,这是一个快速而肮脏的解决方案,只是为了证明它可以工作,毫无疑问会有一些调整和优化。最终,重载
List<T>.Sort(Comparison<T>)
将避免必须动态创建实现T的IComparer的类:
class Program
{
private class Person
{
public string Name { get; set; }
public int Age { get; set; }
public int NumberOfChildren { get; set; }
}
private static List<Person> people = new List<Person>()
{
new Person() { Name="Andrew", Age=35, NumberOfChildren=3},
new Person() { Name="Maria",Age=33,NumberOfChildren=3},
new Person() {Name="Tim",Age=67,NumberOfChildren=4},
new Person() {Name="Tim",Age=62,NumberOfChildren=2},
new Person() {Name="Jim", Age=67,NumberOfChildren=2},
new Person() {Name="Tim",Age=33,NumberOfChildren=0},
new Person() {Name="Bob",Age=35,NumberOfChildren =3},
new Person() {Name="Daisy",Age=1,NumberOfChildren=0}
};
static void Main(string[] args)
{
List<string> sortConditions = new List<string>() { "Age", "Name", "NumberOfChildren" };
var properties = GetSortProperties<Person>(sortConditions);
people.Sort((Person a, Person b) =>
{
int result = 0;
foreach (PropertyInfo prop in properties)
{
result = ((IComparable)prop.GetValue(a, null)).CompareTo(prop.GetValue(b, null));
if (result != 0)
break;
}
return result;
});
}
static List<PropertyInfo> GetSortProperties<T>(List<string> propertyNames)
{
List<PropertyInfo> properties = new List<PropertyInfo>();
var typeProperties = typeof(T).GetProperties();
foreach (string propName in propertyNames)
{
properties.Add(typeProperties.SingleOrDefault(tp => tp.Name == propName));
}
return properties;
}
}