Acumatica using In <> Operator in BQL for integer - operator-keyword

We're trying to use IN operator on BQL to select multiple inventories, but it's not working.
For example,
int[] items = new int[] { 154, 184 };
foreach (SOLine item in PXSelect<SOLine,Where<SOLine.inventoryID,In<Required<SOLine.inventoryID>>>>.Select(this, items))
{
}
I've also referred the blog below that illustrates using the IN operator for a string:
https://asiablog.acumatica.com/2017/11/sql-in-operator-in-bql.html. We are trying for integer type in a similar way. I'm not sure what we're missing. It would be great if some one can help identify.

Acumatica ORM entity DB types are all nullable. You are using an array of non-nullable values 'int[]' instead of an array of nullable values 'int?[]'.
Code:
int?[] items = new int?[] { 154, 184 };
foreach (SOLine item in PXSelect<SOLine,
Where<SOLine.inventoryID,
In<Required<SOLine.inventoryID>>>>.Select(this, items))
{
}

Related

Looping Over a Java Object and Passing One Field to a Mongo Query Similar to SQL WHERE...IN Clause

I am trying to construct a MongoDB equivalent of an SQL WHERE IN clause by iterating over a Java Object List and using one field in that list to fill in the IN data. Using generic example, I would like to build the following command in MongoDB syntax:
SELECT title FROM albums WHERE recorded_year IN ('1967','1968','1969','1970');
The SQL command IN data is extracted from the Album object recordedYear value using the following loop:
if (albums.size() <= 1000) {
sb.append("SELECT title FROM albums WHERE recorded_year");
sb.append(" IN (");
for (int i = 0; i < albums.size(); i++) {
sb.append("'");
sb.append(albums.get(i).getRecordedYear());
sb.append("'");
if (i < albums.size() - 1) {
sb.append(",");
} else {
sb.append(")");
}
}
}
Most Mongo/Java sites I visited seem to deal with command structures using hard-coded values which, while helpful, is completely impractical in real world applications. Any help in pointing to a good tutorial, or if someone has the actual code itself would be greatly appreciated.
Thanks.
But the issue I am having is understanding how to pass a Java Object
list to the to the getAllDocuments...
Make an array of elements which you want to match with the field using the in operator. For example, If you have a someObject.year field, then the array will have the year values; int [] matchYears = { 1989, 2001, 2012 }. Instead of an array you can also use a List collection.
The query:
Bson queryFilter = in("recordedYear", matchYears);
List<Document> result = new ArrayList<>();
collection.find(queryFilter).into(result);
result.forEach(System.out::println);
The queryFilter is built using the com.mongodb.client.model.Filters factory class.
The MongoDB documentation on using the $in operator.
NOTE: The int [] matchYears = { 1989, 2001, 2012 } can be also be created as
int [] matchYears = { javaObject1.recorded_year, javaObject2.recorded_year, ... }.
I didn't quite implement it with BSON, but the logic in the method appears to be working with the code below. Thank you again for your help.
public void getAlbumYears(MongoCollection<Document> collection, List<Album> albums) {
BasicDBObject inQuery = new BasicDBObject();
List<String> year = new ArrayList<>();
for(Album album : albums) {
year.add(album.getYear());
}
inQuery.put("year", new BasicDBObject("$in", year));
for (Document document : collection.find(inQuery)) {
System.out.println(document.toJson());
}
}

Not able to use IN query in LINQ with Entity Framework

I am using EF Framework to retrieve the data from SQL DB.
Sub Request Table looks like below:
In this table "org_assigneddept" is foreign key to another Department Table.
I have list of Departments as Input and I want to retrieve only those rows from DB whose org_assigneddept is matching the list.
Please find my whole code:-
private List<EventRequestDetailsViewModel> GetSummaryAssignedDeptEventRequests(List<EmpRoleDeptViewModel> vmDept)
{
List<EventRequestDetailsViewModel> vmEventRequestDeptSummary = new List<EventRequestDetailsViewModel>();
RequestBLL getRequestBLL = new RequestBLL();
Guid subRequestStatusId = getRequestBLL.GetRequestStatusId("Open");
using (var ctxGetEventRequestSumm = new STREAM_EMPLOYEEDBEntities())
{
vmEventRequestDeptSummary = (from ers in ctxGetEventRequestSumm.SubRequests
where vmDept.Any(dep=>dep.DeptId == ers.org_assigneddept)
select new EventRequestDetailsViewModel
{
SubRequestId = ers.org_subreqid
}).ToList();
}
}
It is giving the following error at the LINQ Query level:-
System.NotSupportedException: 'Unable to create a constant value of
type 'Application.Business.DLL.EmpRoleDeptViewModel'. Only primitive
types or enumeration types are supported in this context.'
Please let me know as how can I achieve the result
You cannot pass the department VMs to SQL, it doesn't know what those are.
// Extract the IDs from the view models.. Now a list of primitive types..
var departmentIds = vmDept.Select(x => x.DeptId).ToList();
then in your select statement...
..
where departmentIds.Contains(id=> id == ers.org_assigneddept)
..

CouchDB Map/Reduce view query from Ektorp

I'm trying to execute a query from java against a Map/Reduce view I have created on the CouchDB.
My map function looks like the following:
function(doc) {
if(doc.type == 'SPECIFIC_DOC_TYPE_NAME' && doc.userID){
for(var g in doc.groupList){
emit([doc.userID,doc.groupList[g].name],1);
}
}
}
and Reduce function:
function (key, values, rereduce) {
return sum(values);
}
The view seems to be working when executed from the Futon interface (without keys specified though).
What I'm trying to do is to count number of some doc types belonging to a single group. I want to query that view using 'userID' and name of the group as a keys.
I'm using Ektorp library for managing CouchDB data, if I execute this query without keys it returns the scalar value, otherwise it just prints an error saying that for reduce query group=true must be specified.
I have tried the following:
ViewQuery query = createQuery("some_doc_name");
List<String> keys = new ArrayList<String>();
keys.add(grupaName);
keys.add(uzytkownikID);
query.group(true);
query.groupLevel(2);
query.dbPath(db.path());
query.designDocId(stdDesignDocumentId);
query.keys(keys);
ViewResult r = db.queryView(query);
return r.getRows().get(0).getValueAsInt();
above example works without 'keys' specified.
I have other queries working with ComplexKey like eg:
ComplexKey key = ComplexKey.of(userID);
return queryView("list_by_userID",key);
but this returns only a list of type T (List) - using CouchDbRepositorySupport of course - and cannot be used with reduce type queries (from what I know).
Is there any way to execute the query with reduce function specified and a complex key with 2 or more values using Ektorp library? Any examples highly appreciated.
Ok, I've found the solution using trial and error approach:
public int getNumberOfDocsAssigned(String userID, String groupName) {
ViewQuery query = createQuery("list_by_userID")
.group(true)
.dbPath(db.path())
.designDocId(stdDesignDocumentId)
.key(new String[]{userID,groupName});
ViewResult r = db.queryView(query);
return r.getRows().get(0).getValueAsInt();
}
So, the point is to send the complex key (not keys) actually as a single (but complex) key containing the String array, for some reason method '.keys(...)' didn't work for me (it takes a Collection as an argument). (for explanation on difference between .key() and .keys() see Hendy's answer)
This method counts all documents assigned to the specific user (specified by 'userID') and specific group (specified by 'groupName').
Hope that helps anybody executing map/reduce queries for retrieving scalar values from CouchDB using Ektorp query.
Addition to Kris's answer:
Note that ViewQuery.keys() is used when you want to query for documents matching a set of keys, not for finding document(s) with a complex key.
Like Kris's answer, the following samples will get document(s) matching the specified key (not "keys")
viewQuery.key("hello"); // simple key
viewQuery.key(documentSlug); // simple key
viewQuery.key(new String[] { userID, groupName }); // complex key, using array
viewQuery.key(ComplexKey.of(userID, groupName)); // complex key, using ComplexKey
The following samples, on the other hand, will get document(s) matching the specified keys, where each key may be either a simple key or a complex key:
// simple key: in essence, same as using .key()
viewQuery.keys(ImmutableSet.of("hello"));
viewQuery.keys(ImmutableSet.of(documentSlug1));
// simple keys
viewQuery.keys(ImmutableSet.of("hello", "world"));
viewQuery.keys(ImmutableSet.of(documentSlug1, documentSlug2));
// complex key: in essence, same as using .key()
viewQuery.keys(ImmutableSet.of(
new String[] { "hello", "world" } ));
viewQuery.keys(ImmutableSet.of(
new String[] { userID1, groupName1 } ));
// complex keys
viewQuery.keys(ImmutableSet.of(
new String[] { "hello", "world" },
new String[] { "Mary", "Jane" } ));
viewQuery.keys(ImmutableSet.of(
new String[] { userID1, groupName1 },
new String[] { userID2, groupName2 } ));
// a simple key and a complex key. while technically possible,
// I don't think anybody actually does this
viewQuery.keys(ImmutableSet.of(
"hello",
new String[] { "Mary", "Jane" } ));
Note: ImmutableSet.of() is from guava library.
new Object[] { ... } seems to have same behavior as ComplexKey.of( ... )
Also, there are startKey() and endKey() for querying using partial key.
To send an empty object {}, use ComplexKey.emptyObject(). (only useful for partial key querying)

Used 'new' operator in LINQ to SQL query, but same instance is referenced in every result

Can anyone explain the behavior I am seeing in the minimal code example below? It seems that for a given field or property, the same two instances of the Entry class are being reused in each iteration of the LINQ to SQL query, even though I use the new operator. The same problem does not show up for LINQ to objects queries. I created a C# console application project using .NET Framework 4 and connecting to a SQL Server 2005 Enterprise database.
public class Set
{
public Entry Field;
public Entry Property { get; set; }
}
public class Entry
{
public int ID;
public string Name { get; set; }
}
class Program
{
static void Main(string[] args)
{
var dc = new DataClasses1DataContext(); // just create a simple dbml with some table from some database
var resultQuery = (
from x in dc.SomeTable
select new Set()
{
Field = new Entry(),
Property = new Entry()
}
);
var sets = resultQuery.ToArray();
Test(sets);
var source = Enumerable.Range(0, 10);
var sourceQuery = (
from x in source
select new Set()
{
Field = new Entry(),
Property = new Entry()
}
);
var sets2 = sourceQuery.ToArray();
Test(sets2);
}
static void Test(Set[] sets)
{
var f = sets[0].Field;
Console.WriteLine(sets.All(x => object.Equals(x.Field, f)));
var p = sets[0].Property;
Console.WriteLine(sets.All(x => object.Equals(x.Property, p)));
Console.Writeline(sets.Length);
Console.WriteLine(object.Equals(f, p));
Console.WriteLine();
}
}
The output of Test() for the LINQ to SQL query is
True
True
1362
False
which indicates that for all of the Set objects produced, all the Field members point to the same single Entry instance and all the Property members point to the same single Entry instance. I.e., the same instance is reused for a respective member in every iteration of the query.
The output of Test() for the LINQ to objects query is
False
False
10
False
which indicates that a new distinct instance is created in each iteration of the query.
Is the LINQ to SQL behavior expected or a bug? Does anyone know if this happens with the Entity Framework?
I don't know if this is a bug or if and why this is expected in LINQ to SQL. I can only answer your last question if that also happens with Entity Framework.
The answer is: No.
With EF you have to use object initializer syntax though when you instantiate the Entry objects. Using the default constructor leads to an exception:
var resultQuery = (
from x in dc.SomeTable
select new Set
{
Field = new Entry { Name = "X" },
Property = new Entry { Name = "X" }
}
);
It doesn't matter how you initialize. Using the code above (and with 4 rows in a small test table) I get this output with your test program:
False
False
4
False
False
False
10
False
It looks that there is a big difference between LINQ to SQL and Entity Framework regarding object materialization during projections.
(I've tested with EF 4.1/DbContext.)
Edit
If I take the modified query in my code snippet above also for your LINQ to SQL query and watch the generated SQL I get the following:
SELECT NULL AS [EMPTY]
FROM [dbo].[SomeTable] AS [t0]
Whereas the same with LINQ to Entites creates this query:
SELECT
1 AS [C1],
N'X' AS [C2],
N'X' AS [C3]
FROM [dbo].[SomeTable] AS [Extent1]
My interpretation is that LINQ to SQL parses the projection code and queries only columns for property values which depend on the "row variable" x. All other properties are filled on the client when the objects get materialized. If an object does not depend on a column value at all, LINQ to SQL creates a single constant object and reuses it in the whole result collection.
In constrast to this Entity Framework also sends constant values (independent of x) to the database server. The values get send back to the client and EF treats those values as if they were column values and updates the properties of the objects in the projection.
This leads also to the big difference that something like this...
Random random = new Random();
var resultQuery = (
from x in dc.SomeTable
select new Set
{
Field = new Entry { ID = random.Next() },
Property = new Entry { Name = "X" }
}
);
...works in LINQ to SQL because apparently the random function value (which is independent of x) is evaluated on the client and then assigned to the property. But EF wants to translate the right side of the property assignment into SQL and send it as SQL fragment to the database server - which fails and leads to the infamous "...cannot translate into store expression..." exception.
Edit 2
BTW: The last code snippet above still creates only a single Field instance in the whole collection: random.Next() is only evaluated once (and also the constructor of Entry is only called once for the Field object). This now is indeed confusing because writing such code one would expect that you want to have a random value for each row returned from the database. It's not the case.

Getting distinct SelectListItem

I am using Linq to get only unique member of a select List item. How do I return a this list...
What I have now is
var queryResult = PatientList.Select(c => c).Distinct();
PatientList = (List<SelectListItem>)queryResult;
I am getting a cast error on the second line. What should an enterprising young developer do?
Try
PatientList = queryResult.ToList();
You version uses casting, which is impossible in this case, as the query result is not a list. ToList constructs a new list, basing on the enumerable against which it is called. It does something like this:
public static List<T> ToList<T>(this IEnumerable<T> collection)
{
return new List<T>(collection);
}
You must be sure, obviously, that PatientList elements are of type SelectListItem and be aware that Distinct() will return the different OBJECTS, but not items with different fields. I.e., if in PatientList you have two independently constructed items with equal Selected, Text and Value properties, you will still have two as a result of the Distinct() call.
Additionally, what is the reason to use Select(c => c)? It effectively does noting.
I don’t know what type are the item in your list but for what you have posted you can call Distinct() directly on the list
List<int> ages = new List<int> { 21, 46, 46, 55, 17, 21, 55, 55 };
IEnumerable<int> distinctAges = ages.Distinct();
Adding .ToList() if you need to convert it to a List