2

ListBoxコントロールを使用すると、データソースをフィードし、DisplayMemberとValueMemberに名前を付けることができます。魔法を使って、データソースのフィールドを表示し、選択した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)を認識せず、使用するレコードのフィールドの3つの名前、ID、Name、およびValueのみを認識します。

フィルタクエリは、次の例のようになります。

var MyTable
    from Record in MySourceTable
    where FilterValue == GivenValue
    select new
    {
        Value = Record.ID,
        Display = Record.Name,
    };

誰かがどこから始めればいいのか教えてもらえますか?

4

3 に答える 3

1

欠落しているものは、クエリのwhere条件にあるようです。次のようになります。

var MyTable = 
    from Record in MySourceTable
    where Record.FilterValue == GivenValue
    select new
    {
        Value = Record.ID,
        Display = Record.Name,
    };

GiveValueは、おそらくFilterValueと比較したいものを含むローカル変数またはプロパティです。ただし、FilterValueは、MySourceTableを作成した最初のクエリで作成した匿名タイプのプロパティです。2番目のクエリでは、Recordはその匿名型のインスタンスであり、クエリの他のすべての部分でインスタンスへの参照を使用して、where句をチェックするかselect句を選択するインスタンスを参照する必要があります。FilterValueをそこに置くだけでは、何を意味するのかわかりません。

于 2012-10-30T22:10:14.583 に答える
0

私は方法を見つけました、それは機能しますが、完全に満足のいく方法ではありません。

「問題」(私の元の質問と比較して)は、ソースのフィルタリングにlinq-to-sqlを使用しないことです。しかし、それは機能し、それは今のところ私にとっては問題ありません。

要約:高レベルのモジュールで、LINQtoSQLステートメントを準備します。これにより、IQueriable <Object>、事実上IQueriableオブジェクトが生成されます。このオブジェクトは、ID用、ディスプレイ用、フィルタリング用の3つの名前とともに下位レベルのモジュールに与えられます。ソースをさらに制御する必要がある場合、たとえば、膨大な結果をもたらすフィルタリングされていないデータや、複雑なLINQtoSQLクエリの場合は、デリゲート関数を使用します。それは私が望むすべてのコントロールを私に与えるでしょう。

低レベルでは、私はIQueriable <Object>を持っており、ワットリフレクションが教えてくれることを除いて、オブジェクトについての知識はまったくありません。コントロール固有の形式で使用したい結果のテーブルを生成します。(レコードクラス)。私の標準コードでは処理できないより複雑なものについては、オブジェクトのリストを作成する必要があるデリゲートを提供します。このオブジェクトには、少なくとも「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;
    }
}
于 2012-11-01T20:00:08.533 に答える
0

プロパティと値を文字列として受け取り、それを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; }
}

したがって、完全な機能を実現するには、これら2つのアイデアを組み合わせて、フィルタリングが機能するようにする必要があります。

ちなみに、このための式ツリーを構築する方法はたくさんあります。ある時点で、私が思う式ツリーを表示するツールがいくつかあったので、手動でlinqクエリを記述してその方法を確認できます。 Netは式を作成し、このコードを変更してそれに基づいて作成し、より効率的な式ツリーを取得できるようにします。

于 2012-11-01T20:51:04.387 に答える