4

バックグラウンド

私は Microsoft Dynamics CRM 2011 QueryExpressions を使用しています。これは、CRM 以外のすべての人にとって、選択している列の文字列名を入力する必要があるデータベースにアクセスするために SDK を使用していることを知っているだけです。カスタム ColumnSet クラスで:

new ColumnSet("personid", "name", "age");

SDK はアーリー バインド クラスを生成するため、すべてのデータベース テーブル用のクラスがあり、アーリー バインド クラスにはすべて、オブジェクトに取り込まれたテーブルの列をキーとするディクショナリがあります。すなわち:

var p = new Person { Name = "John", Age = 39, SSN = null };
p.Attributes.Count == 3;
// p.Attributes.Keys == { "name", "age", "ssn" };

問題

ColumnSet に入力するときに 3 つの問題があります

  1. クラス/テーブルに含まれる列を忘れました
  2. いくつかの列をファット フィンガーしても、実行時までエラーは発生しません
  3. ColumnSet をインスタンス化するとき、列名はすべて小文字にする必要がありますthissillyexampleisntthatreadableThisSillyExampleIsntThatReadable

これら 3 つの問題はすべて、早期バインディングによって解決できます。

クラスのすべての列、つまり new ColumnSet(PersonColumns.PersonId, PersonColumns.Name, PersonColumns.Age) を含む各クラスの列挙型またはスタクトを作成できることはわかっていますが、既に生成されているクラスを使用したい.

私の最善の試み

私が現在思いつくことができる最高のものはこれです:

ColumnSetFactory.Create<Person>(p => p.PersonId = null, p.Name = null, p.Age = null);

ここで、Create は型 T (この例では person) のオブジェクトを受け取り、オブジェクトのディクショナリを調べて、ColumnSet を生成して返します。

目標

事前にバインドされたクラスを利用して ColumnSet を生成する汎用関数を用意します。

ColumnSetFactory.Create<Person>(p => p.PersonId, p.Name, p.Age);

何か案は?

4

2 に答える 2

3

残念ながら、試行/目標の構文は C# では機能しませんが、おそらくそれに近いものを得ることができます。

私はダイナミクス crm に精通していないので、この仮定を行っています。のコンストラクターColumnSetは、可変量の文字列引数を取り、署名を持っています。

public ColumnSet(params string[] arguments)

オブジェクト初期化子を返す (匿名オブジェクトを作成する) ラムダ式を作成し、リフレクションを使用して、初期化子のメンバー バインディングを使用してコンストラクターを呼び出すことができます。あなたが何を達成しようとしているのか理解できれば、オブジェクトの既存のパラメーター名を使用して、それらの名前を基本的にこのコンストラクターに渡してオブジェクトを作成することをお勧めします。

これを行う方法は次のとおりです。

public static ColumnSet Create<T>(Expression<Func<T, object>> parameters)
{
    var initializer = parameters.Body as NewExpression;
    if (initializer == null || initializer.Members == null)
        throw new ArgumentException("lambda must return an object initializer");
    var memberNames = initializer.Members
        .Select(member => member.Name.ToLower())
        .ToArray();
    var ctor = typeof(ColumnSet).GetConstructor(new Type[] { typeof(string[]) });
    return (ColumnSet)ctor.Invoke(new object[] { memberNames });
}

それを使用するには、次のように呼び出します。

ColumnSetFactory.Create<Person>(p => new { p.PersonId, p.Name, p.Age });

// Personally I prefer to call it like this to let the compiler
// infer the generic arguments
ColumnSetFactory.Create((Person p) => new { p.PersonId, p.Name, p.Age });

これにより、コンストラクターへの同等の呼び出しが生成されます。

new ColumnSet("personid", "name", "age");

列名を作成してランダムな値を与えることもできます。値自体は使用されず、メンバーの名前のみが使用されます。

ColumnSetFactory.Create<Person>(p => new
{
    p.PersonId,
    p.Name,
    p.Age,
    Foobar = 0,
    Boo = "rawr!!!",
});

これにより、コンストラクターへの同等の呼び出しが生成されます。

new ColumnSet("personid", "name", "age", "foobar", "boo");
于 2012-07-30T15:45:37.767 に答える
0

ここにはいくつかの可動部分があります。

まず、C#では、実行が遅れるアーリーバウンドのアイテムが必要ですが、残念ながら、希望どおりにそこに到達することはできません。アーリーバウンドは、コンパイル時より前にクラスをビルドします。

したがって、1つのオプションは、必要ないくつかのエンティティに対して独自の簡略化されたアーリーバウンド作成を作成することです(またはMicrosoftアーリーバウンドのものを使用します)

別のオプションは辞書を使用することです-しかし、これはおそらくもっと退屈であることがわかり、問題#3だけを処理します。

これがあなたが探している答えではないことは知っていますが、一歩下がってFetchの使用を検討します。

stunnwareのようなツールを使用すると、フェッチクエリを簡単に作成してテストできるため、探している結果を得ることができます。

次に、フェッチを実行してIList>を返すジェネリック関数を作成します。このようにして、フェッチ内で指定した属性に基づいてフィールドを簡単に参照できます。(問題#1と#2の世話をする)

于 2012-07-31T13:52:35.207 に答える