Left Join in Subsonic3 - subsonic

I'm new in subsonic3, and I'm getting some errors when I try to use LeftJoin
var q =
from c in categories
join p in products on c equals p.Category into ps
from p in ps.DefaultIfEmpty()
select new { Category = c, ProductName = p == null ? "(No products)" : p.ProductName };
The error is
"System.Collections.Generic.Enumerable '...' cannot be used for parameter of type System.Linq.IQueryable
Does anyone had this error before? Did you fix it?
Thanks

I don't know which one is the IQueryable property but you probably know, just add the .AsEnumerable() method.
categories.AsEnumerable() or products.AsEnumerable()
I cant remember if you had to add the toList() method also but you can try it out.
categories.AsEnumerable().toList() or products.AsEnumerable().toList()

Related

FlexibleSearch using enum in WHERE clause

I am working with Hybris and trying to query all the products that have an approval status of APPROVED within Java code. It should look like below, but I cannot get it to work in either HAC, or in Java code.
What is the correct way to do it?
SELECT {p:pk} FROM {Product as p join EnumerationValue as enum on enum.pk = p.approvalStatus } WHERE {enum:code[en]} = 'APPROVED'
Thank you everyone, here is the final answer that works, see comments in other replies for some more questions I have and hopefully some wonderfully wise replies:
final StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("SELECT {p:").append(ProductModel.PK).append("} ");
stringBuilder.append("FROM {").append(ProductModel._TYPECODE).append(" as p join ")
.append(ArticleApprovalStatus._TYPECODE).append(" as enum on {enum.pk} = {p.").append(ProductModel.APPROVALSTATUS).append("} join ")
.append(CatalogVersionModel._TYPECODE).append(" as cv on {cv.pk} = {p.").append(ProductModel.CATALOGVERSION).append("} } ");
stringBuilder.append("WHERE ( {enum:code} = ?approvalStatus1 or {enum:code} = ?approvalStatus2} and {cv:")
.append(CatalogVersionModel.VERSION)
.append("} = ?version");
final String unapprovedString = ArticleApprovalStatus.UNAPPROVED.toString().toLowerCase();
params.put("approvalStatus1", unapprovedString);
params.put("approvalStatus2", ArticleApprovalStatus.UNAPPROVED.toString().toLowerCase());
You need to use the type of the enum. Also, the enum code is case-sensitive; it depends on what is defined in the items.xml.
SELECT * FROM {Product
JOIN ArticleApprovalStatus ON {Product.approvalStatus} = {ArticleApprovalStatus.pk}}
WHERE {ArticleApprovalStatus.code} = 'approved'
Try to wrap the attributes with {} like this:
SELECT {p:pk} FROM {Product as p join EnumerationValue as enum on {enum.pk} = {p.approvalStatus} } WHERE {enum:code[en]} = 'APPROVED'

Kentico 10 ObjectQuery join multiple tables

I am basically trying to run a query that gives me all the Users that have purchased a product with a particular SKU. Essentially this SQL here:
SELECT u.FirstName, u.LastName, u.Email
FROM COM_OrderItem oi INNER JOIN COM_Order o ON oi.OrderItemOrderID = o.OrderID
INNER JOIN COM_Customer c ON o.OrderCustomerID = c.CustomerID
INNER JOIN CMS_User u ON c.CustomerUserID = u.UserID
WHERE oi.OrderItemSKUID = 1013
I was trying to use the ObjectQuery API to try and achieve this but have no idea how to do this. The documentation here does not cover the specific type of scenario I am looking for. I came up with this just to try and see if it works but I don't get the three columns I am after in the result:
var test = OrderItemInfoProvider
.GetOrderItems()
.Source(orderItems => orderItems.Join<OrderInfo>("OrderItemOrderID", "OrderID"))
.Source(orders => orders.Join<CustomerInfo>("OrderCustomerID", "CustomerID"))
.Source(customers => customers.Join<UserInfo>("CustomerUserID", "UserID"))
.WhereEquals("OrderItemSKUID", 1013).Columns("FirstName", "LastName", "Email").Result;
I know this is definitely wrong and I would like to know the right way to achieve this. Perhaps using ObjectQuery is not the right approach here or maybe I can somehow just use raw SQL. I simply don't know enough about Kentico to understand the best approach here.
Actually, the ObjectQuery you created is correct. I tested it and it is providing the correct results. Are you sure that there are indeed orders in the system, which contain a product with SKUID 1013 (you can check that in the COM_OrderItem database table)?
Also, how are you accessing the results? Iterating through the results should look like this:
foreach (DataRow row in test.Tables[0].Rows)
{
string firstName = ValidationHelper.GetString(row["FirstName"], "");
string lastName = ValidationHelper.GetString(row["LastName"], "");
string email = ValidationHelper.GetString(row["Email"], "");
}

WHERE IN with Azure DocumentDB (CosmosDB) .Net SDK

Having seen this question I'm not sure why the following code for my DocDb instance isn't working:
var userApps = _docs.CreateDocumentQuery(UriFactory.CreateDocumentCollectionUri(Constants.Databases.Applications.ID, Constants.Databases.Applications.Collections.USER_APPS),
new SqlQuerySpec(#"SELECT r.appId FROM ROOT r WHERE r.userId = #userId", (#"#userId", userId).ToSqlParameters()))
.ToList()
.Select(s => (string)s.appId);
var query = _docs.CreateDocumentQuery<Document>(UriFactory.CreateDocumentCollectionUri(Constants.Databases.Applications.ID, Constants.Databases.Applications.Collections.APP_DEFINITIONS),
new SqlQuerySpec(#"SELECT r.id, r.appName FROM ROOT r WHERE r.appId IN (#userApps)", (#"#userApps", userApps.ToArray()).ToSqlParameters()),
new FeedOptions { EnableCrossPartitionQuery = true })
.AsDocumentQuery();
When I execute this, though I know the data should be returning me back a result set, it comes back empty every time.
Troubleshooting so far
Variants of .Select()
Return strings that I string.Join in to a comma-separated list.
Eg:
var userApps = string.Join(#",", _docs.CreateDocumentQuery(UriFactory.CreateDocumentCollectionUri(Constants.Databases.Applications.ID, Constants.Databases.Applications.Collections.USER_APPS),
new SqlQuerySpec(#"SELECT r.appId FROM ROOT r WHERE r.userId = #userId", (#"#userId", userId).ToSqlParameters()))
.ToList()
.Select(s => $#"'{s.appId}'");
Don't encapsulate IN parameter
Removing the () around the parameter spec in the query thinking maybe the SqlParameter spec was doing the array specification?
Eg: #"SELECT r.id, r.appName FROM ROOT r WHERE r.appId IN #userApps")
Ends up throwing "Syntax error, incorrect syntax near '#userApps'."
Validate via Azure Portal queries
Ran the (expected) SQL that this code should be running.
I get back my expected results without issue (ie: I know there is a result set for these queries as-written).
Debugger output for Query 1
AppIds are coming back from query 1.
Unsatisfactory workaround
Change query 2 to not be parameterized. Rather, inject the comma-separated list of IDs from query 1 in to it:
var userApps = string.Join(#",", _docs.CreateDocumentQuery(UriFactory.CreateDocumentCollectionUri(Constants.Databases.Applications.ID, Constants.Databases.Applications.Collections.USER_APPS),
new SqlQuerySpec(#"SELECT r.appId FROM ROOT r WHERE r.userId = #userId", (#"#userId", userId).ToSqlParameter()))
.ToList()
.Select(s => $#"'{s.appId}'"));
var query = _docs.CreateDocumentQuery<Document>(UriFactory.CreateDocumentCollectionUri(Constants.Databases.Applications.ID, Constants.Databases.Applications.Collections.APP_DEFINITIONS),
new SqlQuerySpec($#"SELECT r.id, r.appName FROM ROOT r WHERE r.appId IN ({userApps})"),
new FeedOptions { EnableCrossPartitionQuery = true })
.AsDocumentQuery();
Works perfectly but I'm not going to accept it as an answer to this problem as it goes against a couple decades-worth of SQL best practices and, frankly, shouldn't be a solution.
Here's my ToSqlParameters() extension method in case it's the culprit (this works everywhere else I've used it, though. Maybe something special is needed for arrays?):
public static SqlParameterCollection ToSqlParameters(this (string, object) parmDef) => new SqlParameterCollection(new[] { new SqlParameter(parmDef.Item1, parmDef.Item2) });
Thanks!
If you use a parameterized IN list, then it will be considered as a single value when the parameter is expanded.
For instance, for this query:
SELECT * FROM r WHERE r.item IN (#items) And #items is defined as "['val1', 'val2', 'val3']" will be interpreted as such:
SELECT * FROM r WHERE r.item IN (['val1', 'val2', 'val3'])
which basically means that you're comparing r.item to a single value that is an array of three elements (i.e. equivalent to r.item = ['val1', 'val2', 'val3']).
To compare to multiple items, you need to use a parameter for each value. Something like this: SELECT * FROM r WHERE r.item IN (#val1, #val2, #val3])
A more convenient way to write this query is to use ARRAY_CONTAINS instead and pass the array of items as a single parameter. So the above query will be written like this:
SELECT * FROM r WHERE ARRAY_CONTAINS(#items, r.item)

What is wrong in this LINQ Query, getting compile error

I have a list AllIDs:
List<IAddress> AllIDs = new List<IAddress>();
I want to do substring operation on a member field AddressId based on a character "_".
I am using below LINQ query but getting compilation error:
AllIDs= AllIDs.Where(s => s.AddressId.Length >= s.AddressId.IndexOf("_"))
.Select(s => s.AddressId.Substring(s.AddressId.IndexOf("_")))
.ToList();
Error:
Cannot implicitly convert type 'System.Collections.Generic.List<string>' to 'System.Collections.Generic.List<MyCompany.Common.Users.IAddress>'
AllIDs is a list of IAddress but you are selecting a string. The compiler is complaining it cannot convert a List<string> to a List<IAddress>. Did you mean the following instead?
var substrings = AllIDs.Where(...).Select(...).ToList();
If you want to put them back into Address objects (assuming you have an Address class in addition to your IAddress interface), you can do something like this (assuming the constructor for Address is in place):
AllIDs = AllIDs.Where(...).Select(new Address(s.AddressID.Substring(s.AddressID.IndexOf("_")))).ToList();
You should also look at using query syntax for LINQ instead of method syntax, it can clean up and improve the readability of a lot of queries like this. Your original (unmodified) query is roughly equivalent to this:
var substrings = from a in AllIDs
let id = a.AddressId
let idx = id.IndexOf("_")
where id.Length >= idx
select id.Substring(idx);
Though this is really just a style thing, and this compiles to the same thing as the original. One slight difference is that you only have to call String.IndexOf() one per entry, instead of twice per entry. let is your friend.
Maybe this?
var boundable =
from s id in AllIDs
where s.AddressId.Length >= s.AddressId.IndexOf("_")
select new { AddressId = s.AddressId.Substring(s.AddressId.IndexOf("_")) };
boundable = boundable.ToList();

JPQL query --- how to use 'is null'

i use the following query in JPQL to query the people whose address column is empty.
List rl =
em.createQuery( "select o from Person as o where
o.address IS NULL" ).setFirstResult(
0).setMaxResults( 50).getResultList();
...
this line of code always return an empty list, obviously the table does has entries that match the condition.
class Person {
Address address;
String name;
... }
class Address {
String name;
... }
anyone knows what's wrong with this jpql statement?
thanks in advance.
As mentioned, address column is empty, then try using IS EMPTY expression instead of IS NULL.
em.createQuery( "SELECT o FROM Person o where (o.address.id IS NULL OR o.address.id = 0").setMaxResults(50).getResultList();
Check constraint according to id's datatype.
Also there is no need to mention setFirstResult(0) as it is not going to skip any results & without it, by default all matching results will be fetched.

Resources