Query results don't match NumFound when using SolrNet with VB.NET - vb.net

I have implemented SolrNet in a VB.NET web site and it's working perfectly with one exception. My results object may tell me that 10 matching "documents" have been found but the collection only contains 9.
My collection always contains 1 less than the NumFound property states. I have run the queries directly through my Solr instance and I know that the NumFound property is reflecting the correct value. Having reviewed the returned documents I can see that the first document in each result set is missing from my collection i.e. the one at position 0.
This seems like a problem connected to a zero indexed collection.
I can't see that I'm doing anything wrong and suspect that this is a bug. Has anyone else experienced this or can you suggest where I may have gone wrong?
Source code is as follows
Private Prods As New SolrQueryResults(Of BLL.solrProduct)
Dim solr As ISolrOperations(Of BLL.solrProduct) = ServiceLocator.Current.GetInstance(Of ISolrOperations(Of BLL.solrProduct))()
Dim SolrQueryOptions As New SolrNet.Commands.Parameters.QueryOptions() With {.Stats = New StatsParameters(), .Start = PagingCurrent, .Rows = PagingSize, .Facet = New FacetParameters() With { _
.MinCount = 1, .Queries = New SolrNet.ISolrFacetQuery() {New SolrFacetFieldQuery("brand")}}}
SolrQueryOptions.Stats.AddField("selling_price")
SolrQueryOptions.FilterQueries.Add(New SolrQueryByField("brand", "puma"))
Prods = solr.Query("shirt", SolrQueryOptions)
PagingTotal = Prods.NumFound 'This returns 10
lv_prods.DataSource = Prods
lv_prods.DataBind() 'This renders 9 items

Solr pagination is zero-based, i.e. the first item corresponds to Start=0

Related

VB.net - SQLite query response turning empty after first interaction

so I'm using SQLite in a VB.net project with a populated database. I'm using the Microsoft.Data.Sqlite.Core and System.Data.SQLite NuGet package libraries. So the problem presents when I'm trying to get the result of a query. At first the SQLiteDataReader gets the response and all the elements of the desired table. I know this cause in the debugger I have a breakpoint after the setting the object and when I check the parameters of the SQLiteDataReader object the Result View shows all the elements of my table, but as soon as I remove the mouse from the object and check it again the Result View turns out empty, without even resuming with the next line of code. Does anyone know if its a known bug or something cause Ive used this exact method of querying a table in another project and it works.
The code:
Public Function RunQuery(com As String)
If CheckConnection() Then
command.CommandText = com
Dim response As SQLiteDataReader
response = command.ExecuteReader
Dim len As Integer = response.StepCount
Dim col As Integer = response.FieldCount
Dim resp(len, col) As Object
For i = 0 To col - 1
Using response
response.Read()
For j = 0 To len - 1
resp(i, j) = response.GetValue(j)
Next
End Using
Next
Debugger with populated result view
Debugger with empty result view
edit: added the for loop to show that its not only on the debugger that the result view is empty. When using response.Read() it throws an exception "System.InvalidOperationException: 'No current row'"
As I have told you in the comment, a DataReader derived class is a forward only retrieval object. This means that when you reach the end of the records returned by the query, that object is not capable to restart from the beginning.
So if you force the debugger to enumerate the view the reader reaches the end of the results and a second attempt to show the content of the reader fails.
The other part of your problem is caused by a misunderstanding on how to work on the reader. You should loop over the Read result not using a StepCount property. This property as far as I know, is not standard and other data providers don't support it. Probably it is present in the SQLite Provider because for them it is relatively easy to count the number of records while other providers don't attempt do calculate that value for performance reasons.
However, there are other ways to read from the reader. One of them is to fill a DataTable object with its Load method that conveniently take a DataReader
Dim data As DataTable = New DataTable()
Using response
data.Load(response)
End Using
' Now you have a datatable filled with your data.
' No need to have a dedicated bidimensional array
A DataTable is like an array where you have Rows and Columns instead of indexes to iterate over.

Error HRESULT E_FAIL when iterating through for loop only

I'm seeing the good old "System.Runtime.InteropServices.COMException HResult=0x80004005 Message=Error HRESULT E_FAIL has been returned from a call to a COM component" error when attempting to find an item via a for loop as shown below:
For i = 1 to itemList.Count
oObject = itemList.Item(i)
Next
But not if I hardcode the index, this finds item 1 without issue:
oObject = itemList.Item(1)
Obviously I don't want to do that and need to search through all the objects in my "itemList" to find the one I'm looking for.
I'm being intentionally vague because the software I'm working in is Dassault 3D Experience but am writing macros for it through Visual Studio 2017. I'm not sure where to even start debugging this sort of issue so any suggestions would be appreciated. Thanks.
Edit: adding full code of what I'm trying to do here (find an object, display its name, also select it on screen to double check. I will later add a check to make sure the object found in each loop is really what I'm looking for). All variables have been declared before this section.
selactive = CATIA.ActiveEditor.Selection
selactive.Clear()
product1Service = CATIA.ActiveEditor.GetService("PLMProductService")
oRootOcc = product1Service.RootOccurrence
cVPMOccurrences = oRootOcc.Occurrences
For i = 1 to cVPMOccurrences.Count
oVPMOccurrence = cVPMOccurrences.Item(i)
selactive.Add(oVPMOccurrence)
MsgBox(oVPMOccurrence.Name)
Next
The line that fails is oVPMOccurrence = cVPMOccurrences.Item(i)
Can you do something like this with a For Each loop?
For each oVPMOccurrence as oRootOcc.Occurrence in cVPMOccurrences.Items
selactive.Add(oVPMOccurrence)
MsgBox(oVPMOccurrence.Name)
Next
Using a For Each means you don't have to worry at all about the index
Not sure what the type of oVPMOccurrence is as you haven't specified
Most indexes in .net are zero base. I don't know what itemList is but I suspect the index of the first item is 0.
For i = 0 to itemList.Count - 1
oObject = itemList.Item(i)
Next
Not sure why you want to overwrite the value of oObject on every iteration.

LINQ Count problems while trying to access to subList from a List of Objects (VB.NET)

I'm having a pretty tough time figuring it out why it doesn't work properly but I'm asking for it.
Dim goodCount As Integer = (From item In equipmentTagList
Where item.Importance = "Critique"
Where item.Status <> TargetRange.OutOfRange
Select item).Count()
Dim badCount As Integer = (From item In equipmentTagList
Where item.Importance = "Critique"
Where item.Status.Contains(TargetRange.OutOfRange)
Select item).Count()
EquipmentTagList is a List(Of MachineTag) (custom object) so I want to get how many MachineTag from the EquipmentTagList matches the criteria. I'm still confused about why the first one works but not the other one. I know by debugging that the first one returns at least one result while the other returns nothing... I've searched a lot to get help for this error but unfortunately found nothing...
Thanks for helping me out.
EDIT:
The error I get is :
System.InvalidOperationException with Object reference not set to an instance of an object
Assuming for the moment that item.Status is an Integer data type (inferred from your use of TargetRange.OutOfRange as though it's an Enum), the syntax in your second snippet would be expected to fault.
The .Contains() method is reserved for use with IEnumerable objects, not Integer values.
If you modify your code slightly, to this:
Dim badCount = (From item In equipmentTagList
Where item.Importance = "Critique"
Where item.Status.Contains(TargetRange.OutOfRange)
Select item)
...and then set a breakpoint at some point after this call, you'll note that badCount is Nothing. Since Nothing can't have a .Count, the call fails.
Your first snippet is correct—as you've already pointed out.
EDIT
Something's not right here. Your code shouldn't even compile.
Here's what I'm getting:
So item.Status certainly can't be an Integer.
Maybe this will make it a bit easier. You can group by Status after filtering by Importance:
Dim items = From i In equipmentTagList Where i.Importance = "Critique"
Dim counts = items.ToLookup(Function(i) i.Status <> TargetRange.OutOfRange)
Dim goodCount = counts(True).Count()
Dim badCount = counts(False).Count()

Add Custom Field to QuickBooks Estimate from Customer using VB.NET and QBFC Library

For the life of me, I just cannot seem to get this to work. Here is the situation: I am trying to add the already existing customer custom field (already had a definition, but no value) to an estimate that I am currently creating via QBSDK 12. So far, I can add the estimate, the custom fields to the line items, but not the custom fields belonging to the customer in the estimate header area (reserved for customer information).
Here is my attempted code for the header (doesn't work):
If Not (DE.sconProof(x) Is Nothing) Or Not (DE.sconProof(x) = "") Then
Dim DataExtModRq As IDataExtMod
DataExtModRq = requestMsgSet.AppendDataExtModRq
' DataExtModRq.ORListTxn.TxnDataExt.TxnID.SetValue(sEstID)
DataExtModRq.OwnerID.SetValue("0")
DataExtModRq.DataExtName.SetValue("Proof Required")
DataExtModRq.ORListTxn.TxnDataExt.TxnDataExtType.SetValue(ENTxnDataExtType.tdetEstimate)
DataExtModRq.ORListTxn.ListDataExt.ListObjRef.FullName.SetValue(DE.sconCompany(x))
DataExtModRq.DataExtValue.SetValue(DE.sconProof(x))
End If
Here is my working code for line items within the estimate (Does work):
If Not DE.sitemDateNeeded(i) = "" Then
Dim DataExt53 As IDataExt
DataExt53 = EstimateLineAdder.EstimateLineAdd.DataExtList.Append()
'Set field value for OwnerID
DataExt53.OwnerID.SetValue("0")
DataExt53.DataExtName.SetValue("In Hands By")
'Set field value for DataExtValue
DataExt53.DataExtValue.SetValue(DE.sitemDateNeeded(i))
End If
If Not DE.sitemSPC(i) = "" Then
Dim DataExt54 As IDataExt
DataExt54 = EstimateLineAdder.EstimateLineAdd.DataExtList.Append
DataExt54.DataExtName.SetValue("SPC")
DataExt54.DataExtValue.SetValue(DE.sitemSPC(i))
End If
The error message say's I am missing the TxnID but I am not modifying the estimate, I am creating a new one. I have tried the "IDataExt" as well but that doesn't work any better. If I need to save the newly created estimate, and then go back and add the TxnID, that would be really weird, and I'm not sure of a simple way to do that. I should be able to add data to the custom field in the header portion of the estimate without going through so much "hoopla". Please help me if you know the answer.
I figured it out...
If Not (DE.sconProof(x) Is Nothing) Or Not (DE.sconProof(x) = "") Then
Dim DataExtModRq As IDataExtMod
DataExtModRq = requestMsgSet.AppendDataExtModRq
DataExtModRq.DataExtName.SetValue("Proof Required")
DataExtModRq.DataExtValue.SetValue(DE.sconProof(x))
DataExtModRq.OwnerID.SetValue("0")
'DataExtModRq.ORListTxn.TxnDataExt.TxnDataExtType.SetValue(ENTxnDataExtType.tdetEstimate)
DataExtModRq.ORListTxn.ListDataExt.ListDataExtType.SetValue(ENListDataExtType.ldetCustomer)
DataExtModRq.ORListTxn.ListDataExt.ListObjRef.FullName.SetValue(DE.sconCompany(x))
'DataExtModRq.ORListTxn.TxnDataExt.TxnID.SetValue(sTxnID)
End If

ComboBox DataBinding DisplayMember and LINQ queries

Update
I decided to iterate through the Data.DataTable and trimmed the values there.
Utilizing SirDemon's post, I have updated the code a little bit:
Sub test(ByVal path As String)
Dim oData As GSDataObject = GetDataObj(path)
EmptyComboBoxes()
Dim oDT As New Data.DataTable
Try
Dim t = From r In oData.GetTable(String.Format("SELECT * FROM {0}gsobj\paths ORDER BY keyid", AddBS(path))) Select r
If t.Count > 0 Then
oDT = t.CopyToDataTable
For Each dr As Data.DataRow In oDT.Rows
dr.Item("key_code") = dr.Item("key_code").ToString.Trim
dr.Item("descript") = dr.Item("descript").ToString.Trim
Next
dataPathComboBox.DataSource = oDT
dataPathComboBox.DisplayMember = "descript"
dataPathComboBox.ValueMember = "key_code"
dataPathComboBox.SelectedIndex = 0
dataPathComboBox.Enabled = True
End If
Catch ex As Exception
End Try
End Sub
This works almost as I need it to, the data is originally from a foxpro table, so the strings it returns are <value> plus (<Field>.maxlength-<value>.length) of trailing whitespace characters. For example, a field with a 12 character length has a value of bob. When I query the database, I get "bob_________", where _ is a space.
I have tried a couple of different things to get rid of the whitespace such as:
dataPathComboBox.DisplayMember.Trim()
dataPathComboBox.DisplayMember = "descript".Trim.
But nothing has worked yet. Other than iterating through the Data.DataTable or creating a custom CopyToDataTable method, is there any way I can trim the values? Perhaps it can be done in-line with the LINQ query?
Here is the code I have so far, I have no problem querying the database and getting the information, but I cannot figure out how to display the proper text in the ComboBox list. I always get System.Data.DataRow :
Try
Dim t = From r In oData.GetTable("SELECT * FROM ../gsobj/paths ORDER BY keyid") _
Select r
dataPathComboBox.DataSource = t.ToList
dataPathComboBox.SelectedIndex = 0
'dataPathComboBox.DisplayMember = t.ToList.First.Item("descript")
dataPathComboBox.Enabled = True
Catch ex As Exception
Stop
End Try
I know that on the DisplayMember line the .First.Item() part is wrong, I just wanted to show what row I am trying to designate as the DisplayMember.
I'm pretty sure your code tries to set an entire DataRow to a property that is simply the name of the Field (in a strongly type class) or a Column (in a DataTable).
dataPathComboBox.DisplayMember = "descript"
Should work if the DataTable contains a retrieved column of that name.
Also, I'd suggest setting your SelectedIndex only AFTER you've done the DataBinding and you know you actually have items, otherwise SelectedIndex = 0 may throw an exception.
EDIT: Trimming the name of the bound column will trim just that, not the actual bound value string. You either have to go through all the items after they've been bound and do something like:
dataPathComboBox.Item[i].Text = dataPathComboBox.Item[i].Text.Trim()
For each one of the items. Not sure what ComboBox control you're using, so the item collection name might be something else.
Another solution is doing that for each item when it is bound if the ComboBox control exposes an onItemDataBound event of some kind.
There are plenty of other ways to do this, depending on what the control itself offers and what you choose to do.
DisplayMember is intended to indicate the name of the property holding the value to be displayed.
In your case, I'm not sure what the syntax will by since you seem to be using a DataSet, but that should be
... DisplayMember="Item['descript']" ...
in Xaml, unless you need to switch that at runtime in which case you can do it in code with
dataPathComboBox.DisplayMember = "Item['descript']"
Again, not 100% sure on the syntax. If you are using a strongly typed DataSet it's even easier since you should have a "descript" property on your row, but given hat your error indicates "System.DataRow" and not a custom type, I guess you are not.
Because I can't figure out the underlying type of the datasource you are using I suggest you to change commented string to
dataPathComboBox.DisplayMember = t.ElementType.GetProperties.GetValue(0).Name
and try to determine correct index (initially it is zero) in practice.