13

UPDATE2リフレクション を使用するというJamesの提案でさらに遊んで、文字列変数に基づいてプロパティ値を返す何かが機能するようになりました。おそらく最善の解決策ではないと思うので、まだこれを答えにしたくありません。コードは次のとおりです。

DataContext dataBase = new DataContext();
List<string> listOfFields = new List<string>;
List<string> listOfUsers = new List<string>


//strFields and strNames are strings generated from listOfFields and listOfUsers
IEnumerable<myUserData> userInfo = dataBase.ExecuteQuery<myUserData>
                       ("select " + strFields + " from myUserData where user_id                          in (" + strNames + ")");    

foreach(var user in userInfo)
{
    foreach(string field in listOfFields)
    {
        string fieldValue = user.GetType().GetProperty(field).GetValue(user,null).ToString
        Console.WriteLine(fieldValue);
    }

}

更新: 私は進歩しています!おもう。これは非常にひどい解決策であり、リソースを浪費する可能性があります。まだわかりませんが、これまでに得た空白の画面よりはましです。現在の問題は、フィールド名ではなく値を返す方法を見つけることです。これが私のコードです:

foreach(string userID in listOfUserIDs)
{
    //dataBase is a Datacontext
    var userInfo = dataBase.myTable
                   .Where("user_id == @0", userID)
                   .Select("New(" + strFields + ")");

    foreach(var user in userInfo)
    {
         Console.WriteLine(user);
    }
}

これにより、{first_name = JOHN, last_name = DOE} など、その他のフィールドが出力されます。Select 句を変更して値のみを選択する方法を見つけられることを願っています。


私は初心者のプログラマーであり、特に C# やデータベースを扱うものは初めてです。これは、クエリとデータベースを扱う最初のプロジェクトであり、動的クエリに基づいて結果を正常に返す際に問題が発生しています。

正しい情報を取得するクエリの作成に成功しましたが、取得された特定のフィールドにアクセスする方法がわかりません。

IEnumerable<myTable> userInfo = dataBase.ExecuteQuery<myTable>
("select " + Fields + " from myTable where userID in                 
(" + userNames + ")");

編集:私の悪い命名規則を許してSystem.Collections.Generic.IEnumerable<DatabaseConnection.myTable>{System.Data.Linq.SqlClient.SqlProvider.OneTimeEnumerable<DatabaseConnection.myTable>} ください. Tables フォルダー内にありました XD

myTable は型クラス DatabaseConnection です。Fields は検索しているフィールドの文字列であり、userNames はそれぞれコンマで区切られた複数のユーザー名の文字列です。例: Fields = "firstName, lastName, idNumber" userNames = "John, Jane, Bob"

私の質問は、現在返されているオブジェクト タイプの各ユーザーの各フィールドを反復処理することは可能ですか? 私はそれが次のように明示的に行われるのを見ただけです:

    foreach(var x in userinfo)
{
        Console.Writeline(x.firstName);
}

私の現在の状況では、ユーザーは特定のユーザー名に関連する他のフィールドを必要とする可能性があるため、これは機能しません。

Dynamic Linq Library も使用してみましたが、選択文字列を正常に設定できましたが、userID が複数の異なる文字列に等しい場合に where 句を正しく設定する方法がわかりません。(名前の数は必ずしも同じではありません)

var dataInfo = dataBase.myTable
                       .Where("userID == @0", "(" + userIDs + ")")
                       .Select("New(" + fields + ")");

私はこれで何日も立ち往生しています。どんな助けでも大歓迎です。多分私は解決策がこれには単純すぎると思っていますか?最初のコードで GetProperties() などを使用できるようにすべきだと思います。

これが回答されていて、フォーマットが不十分である場合も、申し訳ありません(最初の投稿はこちら)。調査中に、探しているものが見つからないか、コードを正しく理解していない可能性があります。助けてくれてありがとう!

編集:これはすべて、私が現在取り組んでいる Excel アドイン用です。各フィールドの結果を特定のセルに配置できるように、情報をリストまたは何らかの形式のオブジェクトに取得する必要があります。

編集:間違った用語を使用していたらすみません。私の間違いは Enumerable 型にあるようで、「myTable」という名前を付けると混乱する可能性があります。これは、プロジェクトの .dbml ファイルでサーバー エクスプローラーから抽出したテーブルです。

編集:個々のユーザーごとにクエリを実行し、その1つのユーザー名に対して要求された各フィールドを取得するのは、どれほどひどく非効率的で時間がかかりますか? これが単純なループを追加する必要があるだけのものである場合、私はばかげていると感じるでしょう。

4

4 に答える 4

1

LINQ to SQLを使用しているように見えるので、LINQを使用してデータをクエリします。MyTableDataContextモデルを作成し、それがモデル内の要素に何らかのユーザー情報を含んでいると仮定します。

using (MyDataContext db = new MyDataContext()) {

    var results = (from m in db.MyTable
                   where m.UserId == userId
                   select m);

    // Loop over all of the rows returned by the previous query and do something with it
    foreach (var m in results) {
        // m represents a single row in the results, do something with it.
        Console.WriteLine(m.UserId);
    }

}

または、クエリが1行のみを返すことを期待している場合は、結果のコレクションではなく、結果を単一のオブジェクトに投影するSingleか、使用することができます。SingleOrDefault

using (MyDataContext db = new MyDataContext()) {

    var singleResult = (from m in db.MyTable
                        where m.UserId == userId
                        select m).SingleOrDefault();

    // Do something with the single result
    if (singleResult != null) {
        Console.WriteLine(singleResult.UserId);
    }

}

編集:

前の例では、LINQを使用して互換性のあるデータソースをクエリする方法の基本を扱います。ほとんどのLINQプロバイダー(使用しているようなLINQ to SQLなど)はIQueryableインターフェイスをサポートしています。簡単に説明すると、このインターフェイスを使用すると、クエリを動的に構築でき、実際に結果にアクセスしようとしている最後の最後まで、そのクエリの実際の実行を延期できます。LINQクエリによって返されるオブジェクト(results最初の例の変数など)はIQueryableを返します。ここで、Tはクエリしたオブジェクトのタイプです。List<T>これは、要素がすでに存在するか、明示的に追加または削除される、と考えるのと同じ意味でのコレクションではありません。最初の例でresultsは、実際には、foreachループは結果を反復しようとします。

フィルタリングシナリオを処理するためにresults、ニーズを満たすまでクエリを作成し続け、準備が整ったときに実行します。

まず、フォームにフィルタリングする3つのフィールド(名、名前、ユーザーID)があると仮定します。簡単にするために、これらのフィールドは正確TextBoxesであり、対応するに入力がある場合は、フィールドでフィルタリングすることがわかっていますTextBox。また、検証は不要であり、ユーザーは常に正しいデータをフィルターに入力すると仮定します。

using (MyDataContext db = new MyDataContext()) {

    // Build out your base query, which would return everything from MyTable
    var results = (from m in db.MyTable
                   select m);

    // Check each textbox for a value to filter by.  Add the filter to the base
    // query where necessary.    

    if(!string.IsNullOrEmpty(txtUserId.Text)) {
        results = results.Where(x => x.UserId == (int) txtUserId.Text);
    }

    if(!string.IsNullOrEmpty(txtFirstName.Text)) {
        results = results.Where(x => x.FirstName == txtFirstName.Text);
    }

    if(!string.IsNullOrEmpty(txtLastName.Text)) {
        results = results.Where(x => x.LastName == txtLastName.Text);
    }

    // Loop over all of the rows returned by the previous query and do something with it.  
    // THIS is the actual point that the SQL would be generated from the query you've 
    // built and executed against the DB.  The elements returned by `results` 
    // should only meet all of the filters that you the user entered for one or
    // more of the fields.  Not entering any data would have resulted in all rows being
    // returned
    foreach (var m in results) {
        // m represents a single row in the results, do something with it.
        Console.WriteLine(m.UserId);
    }

}

上記の例は非常に単純ですが、特定の数のフィールドを一緒にANDしたい典型的なフィルタリングシナリオを表しています。クエリフィルターの構築をカプセル化するためのより洗練された方法があると確信していますが、コアコンセプトは同じです。IQueryable<T>インターフェイスを使用して、フィルタ式をそのインターフェイスにチェーンするだけです。

これを行うと、ANDを使用して述語を連鎖させることしかできず、「ユーザーのIDが6であるか、名が「John」である場合」のようなことはできません。System.Linq.Expressions名前空間を 使用してこれらのようなより複雑な式を作成してLINQ式を作成できますが、これらは比較的複雑であり、ほとんどのシナリオでは必要ありません。

于 2012-10-01T16:49:08.157 に答える
1

私があなたの問題を正しく理解していて、オブジェクトのすべてのプロパティを(コンパイル時に何であるかを知らずに)繰り返したい場合は、Reflectionを使用できます。

foreach (var prop in userInfo.GetType().GetProperties())
{
    Console.WriteLine("Property name: " + prop.Name);
    Console.WriteLine("Property value: " + prop.GetValue(userInfo, null));
}
于 2012-10-01T14:41:45.907 に答える
0

DataContext(または.NET 4.5)は試していませんが、4.0では動的クラスを使用してフィールドに直接アクセスできます。

IEnumerable<dynamic> userInfo = (from user in users
                                 where user.id equals userId
                                 select new { user.name, user.id /*, ...*/ }).ToList();

foreach (dynamic user in userInfo)
{
    Console.WriteLine(user.name);
    Console.WriteLine(user.id);
    //...
}

dynamicは実行時に解決されるクラスを表すため、コーディング時にインテリセンスがフィールドを表示していなくても、フィールドが正しい限り、機能します。

于 2012-10-09T09:25:29.147 に答える
0

あなたのアップデート2に続いて:

おそらく、ネストされた foreach をいくつかの linq に単純化できます。何かのようなもの:

        PropertyInfo[] props = typeof(MyUserData).GetProperties();

        var results = from info in userInfo
                      from p in props
                      where listOfFields.Contains(p.Name)
                      select new
                      {
                          FieldName= p.Name,
                          UserId= info.UserId,
                          FieldValue= p.GetValue(info, null)
                      };

        foreach (var item in results)
        {
            Console.WriteLine("(userId = {0}) {1} = {2}", item.UserId, item.FieldName, item.FieldValue);
        }
于 2012-10-29T12:24:09.677 に答える