How to write this Linq SQL as a Dynamic Query (using strings)?

余生颓废 提交于 2019-12-18 16:56:58

问题


Skip to the "specific question" as needed. Some background:

The scenario: I have a set of products with a "drill down" filter (Query Object) populated with DDLs. Each progressive DDL selection will further limit the product list as well as what options are left for the DDLs. For example, selecting a hammer out of tools limits the Product Sizes to only show hammer sizes.

Current setup: I created a query object, sent it to a repository, and fed each option to a SQL "table valued function" where null values represent "get all products".

I consider this a good effort, but far from DDD acceptable. I want to avoid any "programming" in SQL, hopefully doing everything with a repository. Comments on this topic would be appreciated.

Specific question:

How would I rewrite this query as a Dynamic Query? A link to something like 101 Linq Examples would be fantastic, but with a Dynamic Query scope. I really want to pass to this method the field in quotes "" for which I want a list of options and how many products have that option.

from   p in db.Products
group  p by p.ProductSize into g
select new Category { 
       PropertyType = g.Key,
       Count = g.Count() }

Each DDL option will have "The selection (21)" where the (21) is the quantity of products that have that attribute. Upon selecting an option, all other remaining DDLs will update with the remaining options and counts.

Edit: Additional notes:

.OrderBy("it.City") // "it" refers to the entire record
.GroupBy("City", "new(City)") // This produces a unique list of City
.Select("it.Count()") //This gives a list of counts... getting closer
.Select("key") // Selects a list of unique City
.Select("new (key, count() as string)") // +1 to me LOL.  key is a row of group
.GroupBy("new (City, Manufacturer)", "City") // New = list of fields to group by
.GroupBy("City", "new (Manufacturer, Size)") // Second parameter is a projection

Product
.Where("ProductType == @0", "Maps")
.GroupBy("new(City)", "new ( null as string)")// Projection not available later?
.Select("new (key.City, it.count() as string)")// GroupBy new makes key an object

Product
.Where("ProductType == @0", "Maps")
.GroupBy("new(City)", "new ( null as string)")// Projection not available later?
.Select("new (key.City, it as object)")// the it object is the result of GroupBy

var a = Product
        .Where("ProductType == @0", "Maps")
        .GroupBy("@0", "it", "City") // This fails to group Product at all
        .Select("new ( Key, it as Product )"); // "it" is property cast though

What I have learned so far is LinqPad is fantastic, but still looking for an answer. Eventually, completely random research like this will prevail I guess. LOL.

Edit:

Jon Skeet had a fantastic idea: cast what I need as IGrouping<string, Product>. Thanks to Jon Skeet! Once you cast the object, you can enumerate over the sets and feed the results in to a separate List.


回答1:


I'm not sure how to do this using Query syntax (as above), but using Method syntax, we can use an Expression<Func< as shown below. This sample works against the AdventureWorks SQL Server database (Products table), and allows you to specify which column to group by using a string (in this sample I have chosen Size)

using System;
using System.Linq;
using System.Linq.Expressions;

namespace LinqResearch
{
    public class Program
    {
        [STAThread]
        static void Main()
        {
            string columnToGroupBy = "Size";

            // generate the dynamic Expression<Func<Product, string>>
            ParameterExpression p = Expression.Parameter(typeof(Product), "p");

            var selector = Expression.Lambda<Func<Product, string>>(
                Expression.Property(p, columnToGroupBy),
                p
            );

            using (LinqDataContext dataContext = new LinqDataContext())
            {
                /* using "selector" caluclated above which is automatically 
                compiled when the query runs */
                var results = dataContext
                    .Products
                    .GroupBy(selector)
                    .Select((group) => new { 
                        Key = group.Key, 
                        Count = group.Count()
                    });

                foreach(var result in results)
                    Console.WriteLine("{0}: {1}", result.Key, result.Count);
            }

            Console.ReadKey();
        }
    }
}



回答2:


If you take a look at C# Bits, the author discusses how to create cascading filters using Dynamic Data. It does not sound like you are using Dynamic Data, but he does have a nice expression builder that might be helpful to you. See BuildQueryBody, and then the following section of extension methods on Iqueryable.

Since you are not using Dynamic Data, you will need to deal with not having access to a "MetaForeignKeyColumn" object, but I suspect his approach might help you with your question.

I hope this helps.



来源:https://stackoverflow.com/questions/2531679/how-to-write-this-linq-sql-as-a-dynamic-query-using-strings

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!