使用ListBox控件,可以为其提供一个DataSource,命名一个DisplayMember和一个ValueMember,通过一些魔术,它将显示DataSource中的一个字段并返回一个选定的ValueMember。它可以使用linq-to-sql结果,甚至不知道它所提供的表格的任何具体信息。
反射和属性不是在做一些魔术吗?它是如何工作的! 我需要做类似的事情,但我不知道从哪里开始。我是LINQtoSQL的初学者。
这就是我想要做的。 我有一个我想要过滤的源表。源表可以是任何东西,但都来自某些DataContext。
var MySourceTable =
from MyRecord in Context.GetTable<MySourceTable>()
select new
{
Value = MyRecord.ID,
Display = MyRecord.Name,
FilterValue = MyRecord.Value
};
在我的控制中,我希望能够在某个给定值上过滤MySourceTable。控件不知道使用了什么表(上例中的MySourceTable),控件只知道它应该使用的记录中的三个名称,ID,Name和Value。
过滤器查询应如下所示。
var MyTable
from Record in MySourceTable
where FilterValue == GivenValue
select new
{
Value = Record.ID,
Display = Record.Name,
};
有人可以告诉我从哪里开始吗?
答案 0 :(得分:1)
看起来你缺少的是查询的where条件。它应该是这样的:
var MyTable =
from Record in MySourceTable
where Record.FilterValue == GivenValue
select new
{
Value = Record.ID,
Display = Record.Name,
};
GivenValue可能是一个局部变量或属性,包含您想要比较FilterValue的任何内容。但FilterValue是您在创建MySourceTable的第一个查询中创建的匿名类型的属性。在第二个查询中,Record是该匿名类型的实例,您必须在查询的所有其他部分中使用该实例的引用来引用要检查where子句或选择select子句的实例。如果您只是将FilterValue放在那里,那么它就不知道您的意思了。
答案 1 :(得分:0)
我找到了一种方法,它起作用但不是一种完全令人满意的方法。
'问题'(与我原来的问题相比)是它不使用linq-to-sql来过滤源。但它确实有效,而且现在对我来说还不错。
回顾: 在高级模块中,我准备一个LINQtoSQL语句,这将导致一些IQueriable&lt; Object&gt;,实际上是一个IQueriable对象。此对象与三个名称一起提供给下级模块,一个用于ID,一个用于显示,一个用于过滤。 当我需要对源进行更多控制时,例如对于将导致巨大结果的未过滤数据或复杂的LINQtoSQL查询,我将使用委托函数。这将给我所有我想要的控制权。
在低级别我有一个IQueriable&lt; Object&gt;并且根本没有关于物体的知识,除了wat反射可以告诉我。我生成一个结果表,我想以控件特定的格式使用。 (记录类)。对于我的标准代码无法处理的任何更复杂的事情,我提供了一个委托,该委托必须产生一些对象列表,其中对象必须至少具有名为“Display”的属性和名为“Value”的属性。其他属性是可能的,但不会被使用。
这是我最终开始工作的解决方案:
public partial class MySelector : UserControl
{
class Record
{
public object Display { get; set; }
public object Value { get; set; }
}
....
public string MyDisplayMember { get; set; }
public string MyValueMember { get; set; }
public string MyExternalMember { get; set; }
....
static Object Filter(MySelector sender, Object criterium)
{
IQueryable source = sender.MySource as IQueryable;
if (source == null) return null;
List<Record> result = new List<Record>();
// drawback: this foreach loop will trigger a unfiltered SQL command.
foreach (var record in source)
{
MethodInfo DisplayGetter = null;
MethodInfo ValueGetter = null;
bool AddRecord = false;
foreach (PropertyInfo property in record.GetType().GetProperties())
{
if (property.Name == sender.MyDisplayMember)
{
DisplayGetter = property.GetGetMethod();
}
else if (property.Name == sender.MyValueMember)
{
ValueGetter = property.GetGetMethod();
}
else if (property.Name == sender.MyExternalMember)
{
MethodInfo ExternalGetter = property.GetGetMethod();
if (ExternalGetter == null)
{
break;
}
else
{
object external = ExternalGetter.Invoke(record, new object[] { });
AddRecord = external.Equals(criterium);
if (!AddRecord)
{
break;
}
}
}
if (AddRecord && (DisplayGetter != null) && (ValueGetter != null))
{
break;
}
}
if (AddRecord && (DisplayGetter != null) && (ValueGetter != null))
{
Record r = new Record();
r.Display = (DisplayGetter == null)
? null
: DisplayGetter.Invoke(record, new object[] { });
r.Value = (ValueGetter == null)
? null
: ValueGetter.Invoke(record, new object[] { });
result.Add(r);
}
}
return result;
}
}
答案 2 :(得分:0)
我编写了一个过滤引擎,它将Property和Value作为字符串,并且能够将其用作where子句。
IQueryable<T> FilterFunction<T>(IQueryable<T> query)
{
ParameterExpression p = Expression.Parameter(typeof(T), "notused");
Expression<Func<T, bool>> wherePredicate =
Expression.Lambda<Func<T, bool>>(
Expression.Equal(
Expression.Call(Expression.Property(p, FilterProperty), "ToString", new Type[0]),
Expression.Constant(FilterValue)), p);
return query.Where(wherePredicate);
}
您应该可以将Expression<Func<T, TResult>>
以类似的方式传入query.Select()
如果我正确理解你的问题,我相信这会有效:
string DisplayProperty = "Name";
string ValueProperty = "ID";
IQueryable<Record> SelectRecordProperties<T>(IQueryable<T> query)
{
ParameterExpression p = Expression.Parameter(typeof(T), "notused");
MethodInfo ctorMethod = typeof(Record).GetMethod("Create");
Expression<Func<T, Record>> selectPredicate =
Expression.Lambda<Func<T, Record>>(
Expression.Call(ctorMethod,
Expression.PropertyOrField(p, DisplayProperty),
Expression.PropertyOrField(p, ValueProperty)), p);
return query.Select(selectPredicate);
}
class Record
{
public static Record Create(string display, string value)
{
return new Record() { Display = display, Value = value };
}
public object Display { get; set; }
public object Value { get; set; }
}
因此,为了您的全部功能,您需要结合这两个想法,以便您的过滤工作。
顺便说一句,有很多种方法可以为此构建表达式树,我在一个点找到了一些可以显示我认为的表达式树的工具,所以你可以手动编写linq查询和看看.Net如何构建表达式,然后修改此代码以基于它构建它以获得更高效的表达式树。