4

What I am trying to do boils down to trying concatenate multiple rows into a single row from a column subquery. In the SQL in MySql this is done with a GROUP_CONCAT function.

I have seen code examples like this that should work:

var qryProd = from prod in db.Products
              group word by prod.category into q
              select new { prod.category,  products = string.Join(',', q.Select(p => p.name)) } ;

I am attempting to run this as a small part in a larger query, and as a Column SubQuery, code looks something like this:

var qry = from cat in db.Category
          select new { 
                 cat.category,
                 products = (from word in db.Products
                             where word.category == cat.category
                             group word by word.category into temp
                             select string.Join(',', temp.Select(p => p.name)))
                 };

I am getting this error:

KeySelector: p.category, 
ElementSelector:new { 
    category = ProjectionBindingExpression: category, 
    name = ProjectionBindingExpression: name, 
 }
' by 'RelationalProjectionBindingExpressionVisitor' failed. This may indicate either a bug or a limitation in Entity Framework. See https://go.microsoft.com/fwlink/?linkid=2101433 for more detailed information.

I doubt there is a bug in the Framework, but wondering if String.Join has not been mapped to the appropriate aggregate function in MySql.

So I was wondering if I would be able to create a custom EF function that could call GROUP_CONCAT directly in the query. This has been a rabbit hole of exploration.

The simplest would have been from: C# call a SQL Server user defined function via Entity Framework in essence here is the method:

public string GetFruit(int customerId)
{
    return Database.SqlQuery<string>("select dbo.fngetfruit(@customerId) fruit", new System.Data.SqlClient.SqlParameter("@customerID", customerId)).Single();
}

The issue is the SqlQuery does not seem to be supported on recent versions of EF, you can run a SQL statement directly off a table set by a DbSet command, but no longer able to run it on a generic type, much-less a data primative.

Then I came across this on how to map an aggregate function more directly into EF: Code first Entity Framework 6.1 Custom Aggregate Function but it seems to be EF 6 centric, and I am currently on 5, and worry about Preview Editions. I tried to implement the code, but one of the classes is not found IStoreModelConvention.

Am I out of luck here, or is there still something I can try here? The only other option I can think to use, and seems to negate most of the reason for using EF is to just map a class to a View that has all the needed logic.

EDIT: The model is quite big, but in essence their are three tables to create a multi-multi relationship:

PRODUCT {
   id varchar(45) Primary Key,
   title varchar(100)
}
KEYWORDS {
   id int Primary Key,
   category varchar(45),
   keyword varchar(45)
}
PRODUCT_KEYWORDS {
   PROD_ID varchar(45),
   KEYWORD_ID int
} // Both columns together compose the Primary Key

I decomposed the query into smaller parts so that it can be easier to put together:

var qryKeywords = from keyword in context.KEYWORDS
    join prodWords in context.PRODUCT_KEYWORDS on keyword.id equals (prodWords.keyword_id)
    select new { prodWords.product_id, keyword.keyword, keyword_id = keyword.id };

var qry = from prod in context.PRODUCTS
    join v1 in context.VENDOR on prod.vendor_id equals (v1.id) into t1
    from vendor in t1.DefaultIfEmpty()
    join b1 in context.BRANDS on prod.brand_id equals (b1.brand_id) into t2
    from brand in t2.DefaultIfEmpty()
    select new {
        product_id = prod.product_id,
        product_title = prod.title,
        brand = brand_name,
        vendor = vendor.name,
        keywords = (from word in qryKeywords
                    where word.product_id == prod.product_id
                    group word by word.product_id into t1
                    select string.Join(',', t1.Select(p => p.keyword))).FirstOrDefault(),
        keyword_ids = (from word in qryKeywords
                    where word.product_id == prod.product_id
                    group word by word.product_id into t1
                    select string.Join(',', t1.Select(p => p.keyword_id))).FirstOrDefault()
    };
    

The qryKeywords is able to generate a valid SQL statement, if I comment out the fields KEYWORDS an KEYWORD_IDS, the main query is also able to produce a valid SQL statement.

This is an attempt to get something that would look like this in the end:

| product_title | keywords                        | keyword_ids    |
| ------------- | ---------                       | -----------    |
| phone         | easy setup,easy to use,warranty | 1003,2004,1095 |

Also remember this is using the MySql provider "Pomelo" for the system/database call level.

Thank you for any help you can offer. This has a lot going on inside, sub-queries, left joins, and aggregate functions.

1
  • could you please show your model and tell us what you want to do?Then it can be more clear. Commented Apr 19, 2021 at 8:58

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.