简体   繁体   English

C#Dynamic Linq / Queries

[英]C# Dynamic Linq/Queries

UPDATE2 I started playing more with James suggestion of using reflection and got something working that will return a property value based on a string variable. UPDATE2我开始更多地使用James建议使用反射并得到一些工作,它将返回基于字符串变量的属性值。 I don't want to put this as an answer just yet though as I feel it is probably not the best solution. 我不想把它作为一个答案,但我觉得它可能不是最好的解决方案。 Here is the code: 这是代码:

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);
    }

}

UPDATE: I am making progress! 更新:我正在取得进展! I think. 我认为。 This could be a very terrible solution and resource hog, I'm not sure yet, but it's better than the blank screens I've been getting. 这可能是一个非常可怕的解决方案和资源匮乏,我还不确定,但它比我一直得到的空白屏幕更好。 The issue now is finding a way to just return the values and not the field name with it. 现在的问题是找到一种方法来返回值而不是字段名称。 Here is my code: 这是我的代码:

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);
    }
}

This outputs {first_name = JOHN, last_name = DOE} etc whatever other fields. 无论其他字段如何,都会输出{first_name = JOHN,last_name = DOE}等。 I'm hoping I can find a way to modify my Select clause to just select the values. 我希望我能找到一种方法来修改我的Select子句,只选择值。


I am a novice programmer and especially new to C# and anything that invovles databases.This is my first project working with queries and databases and I'm running into problems with successfully returning results based on a dynamic query. 我是一名新手程序员,尤其是C#的新手以及任何调用数据库的东西。这是我的第一个使用查询和数据库的项目,我遇到了基于动态查询成功返回结果的问题。

I've successfully created a query that will retrieve the correct information, but I am stumped on how to access the specific fields that were retrieved. 我已成功创建了一个将检索正确信息的查询,但我对如何访问检索到的特定字段感到困惑。

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

EDIT: Excuse my bad naming conventions but myTable is of type: System.Collections.Generic.IEnumerable<DatabaseConnection.myTable>{System.Data.Linq.SqlClient.SqlProvider.OneTimeEnumerable<DatabaseConnection.myTable>} This is just a place holder name and has a specific name in my Database. 编辑:请原谅我的错误命名约定,但myTable的类型为: System.Collections.Generic.IEnumerable<DatabaseConnection.myTable>{System.Data.Linq.SqlClient.SqlProvider.OneTimeEnumerable<DatabaseConnection.myTable>}这只是一个占位符名称并在我的数据库中有一个特定的名称。 It was inside of a Tables folder XD 它位于Tables文件夹XD中

myTable is of type class DatabaseConnection. myTable的类型为DatabaseConnection。 Fields is a string of fields I am looking up, and userNames is a string of several user names each seperated by a comma. Fields是我正在查找的一串字段,而userNames是一个由逗号分隔的多个用户名的字符串。 Examples: Fields = "firstName, lastName, idNumber" userNames = "John, Jane, Bob" 示例:Fields =“firstName,lastName,idNumber”userNames =“John,Jane,Bob”

My question is, is it possible to iterate through each of the fields for each user in the object type I'm currently returning? 我的问题是,是否有可能在我正在返回的对象类型中为每个用户迭代每个字段? I've only seen it done explicitly like this: 我只是这样明确地看到它:

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

In my current situation this will not work, since the user may want other fields pertaining to specific usernames. 在我目前的情况下,这将不起作用,因为用户可能想要与特定用户名相关的其他字段。

I've also tried using the Dynamic Linq Library and while I was able to successfully set up my select string, I'm not sure how to correctly go about setting up my where clause when the userID will equal several different strings. 我也尝试过使用Dynamic Linq Library,虽然我能够成功设置我的选择字符串,但我不确定当userID等于几个不同的字符串时如何正确设置我的where子句。 (the number of names will not always be the same) (名称数量不会总是相同)

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

I've been stuck on this for days now. 我已经被困在这几天了。 Any help would be greatly appreciated. 任何帮助将不胜感激。 Maybe I am thinking the solution is too simple to this? 也许我认为解决方案太简单了? I feel like I should be able to use GetProperties() or something similiar in my first bit of code. 我觉得我应该可以在我的第一段代码中使用GetProperties()或类似的东西。

I am also very sorry if this has been answered and my poor formatting(first post here). 我也很抱歉,如果这已经得到回答,我的格式不佳(这里的第一篇文章)。 During my research I have not been able to find what I'm looking for, or possibly I am just not understanding the code correctly. 在我的研究期间,我无法找到我正在寻找的东西,或者我可能只是没有正确理解代码。 Thanks again for any help! 再次感谢任何帮助!

EDIT: All of this is for an Excel Addin I am currently working on. 编辑:所有这些都是我正在进行的Excel Addin。 I will need to get the information into a List or some form of object that will allow me to place each field result into a specific cell. 我需要将信息放入List或某种形式的对象中,这样我就可以将每个字段结果放入特定的单元格中。

EDIT: Excuse me if I'm using the wrong terminology. 编辑:对不起,如果我使用错误的术语。 I feel like my mistake may be in my Enumerable type and naming it "myTable" could be confusing. 我觉得我的错误可能在我的Enumerable类型中并命名为“myTable”可能会令人困惑。 It is a table pulled out from my Server Explorer in my .dbml file in the project. 它是从项目中的.dbml文件中的服务器资源管理器中提取的表。

EDIT: How terribly inefficient/time consuming is it to run a query on each individual user and retrieve each requested field for that one username? 编辑:在每个用户上运行查询并检索该用户名的每个请求字段,效率是多么低效/耗时? I'm going to feel silly if this is something I just needed to add a simple loop to. 如果这只是我需要添加一个简单的循环,我会感到愚蠢。

If I understand your problem correctly and you want to just iterate over all the properties of the object (without knowing what they are at compile time), you could use Reflection eg 如果我正确理解你的问题并且你想迭代对象的所有属性(不知道它们在编译时是什么),你可以使用Reflection,例如

foreach (var prop in userInfo.GetType().GetProperties())
{
    Console.WriteLine("Property name: " + prop.Name);
    Console.WriteLine("Property value: " + prop.GetValue(userInfo, null));
}

Since it appears you're just using LINQ to SQL, then just use LINQ to query the data. 因为看起来你只是使用LINQ to SQL,所以只需使用LINQ来查询数据。 I am going to assume that you've created a DataContext model and that MyTable is an element in your model contains some sort of user information. 我将假设您已经创建了一个DataContext模型,并且MyTable是模型中的一个元素,其中包含某种用户信息。

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);
    }

}

Alternatively, if you are expecting the query to return one row only then you can just use Single or SingleOrDefault to project the results into a single object, rather than a collection of results: 或者,如果您希望查询仅返回一行,那么您可以使用SingleSingleOrDefault将结果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);
    }

}

Edit: 编辑:

The previous examples handle the basics on how you query a compatible data source using LINQ. 前面的示例处理了有关如何使用LINQ查询兼容数据源的基础知识。 Most LINQ providers (such as LINQ to SQL like you are using) support the IQueryable interface. 大多数LINQ提供程序(例如您正在使用的LINQ to SQL)都支持IQueryable接口。 The short explanation is that this interface allows you to dynamically build up queries, and defers the actual execution of that query until the last possible minute when you are actually trying to access the results. 简短的解释是,此接口允许您动态构建查询,并将该查询的实际执行推迟到您实际尝试访问结果时的最后一分钟。 Objects returned by a LINQ query (such as the variable results in the first example) return an IQueryable, where T is the type of object you've queried. LINQ查询返回的对象(例如第一个示例中的变量results )返回IQueryable,其中T是您查询的对象类型。 It's not exactly a collection in the same sense as you might think of a List<T> , where the elements already exist or are explicitly added or removed. 它并不是一个与您可能想到的List<T>相同的集合,其中元素已经存在或明确添加或删除。 In the first example, results doesn't actually have any elements in it until the foreach loop attempts to iterate over the results. 在第一个示例中,在foreach循环尝试迭代结果之前, results实际上不包含任何元素。

To handle your filtering scenario, let's continue to build out the results query until it meets your needs, and then we'll execute it when it's good and ready. 为了处理您的过滤方案,让我们继续构建results查询,直到它满足您的需求,然后我们将在它完好并准备就绪时执行它。

First lets assume that your form has three fields you want to filter by: First Name, Last Name, and User ID. 首先,假设您的表单包含三个要筛选的字段:名字,姓氏和用户ID。 To keep it simple, these fields are just TextBoxes and we know to filter by a field if there is any input at all in its corresponding TextBox . 为了简单TextBoxes ,这些字段只是TextBoxes ,如果在相应的TextBox有任何输入,我们知道要按字段过滤。 Let's also assume that no validation is required, and the user will always enter the correct data into the filter. 我们还假设不需要验证,用户将始终将正确的数据输入过滤器。

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);
    }

}

The above example is pretty simple, but it represents the typical filtering scenario where you would want to AND a certain number of fields together. 上面的示例非常简单,但它代表了典型的过滤方案,您可能希望将一定数量的字段与AND组合在一起。 I'm sure there are more elegant way to encapsulate building out the query filter, but the core concept will still be the same. 我确信有更优雅的方法来封装构建查询过滤器,但核心概念仍然是相同的。 Simply use the IQueryable<T> interface and chain your filter expressions on to it. 只需使用IQueryable<T>接口并将过滤器表达式链接到它。

Doing this only allows you to chain together predicates using AND, and you can't do something like "Where a user has an ID of 6 OR has a first name of 'John'". 这样做只允许您使用AND将谓词链接在一起,并且您不能执行类似“用户的ID为6或名称为'John'”的操作。 You can build more complex expressions like these using the System.Linq.Expressions namespace to build out LINQ expressions, but those are relatively complex and not necessary in most scenarios. 您可以使用System.Linq.Expressions命名空间构建更复杂的表达式来构建LINQ表达式,但这些表达式相对复杂,在大多数情况下都不是必需的。

Though i haven't tried DataContext (or .NET 4.5 at all), in 4.0 you can use the dynamic class to access fields directly: 虽然我还没有尝试过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 represents a class which is resolved at runtime, so even if, when coding, you can't see intellisense showing the fields, as long as they are correct, it will work. dynamic表示在运行时解析的类,因此即使在编码时,您也看不到显示字段的intellisense,只要它们是正确的,它就可以工作。

Following your update 2: 更新后2:

You can probably simplify the nested foreach into some linq. 您可以将嵌套的foreach简化为某些linq。 Something like: 就像是:

        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);
        }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM