Dealing with LINQ to Objects when object not found - vb.net

I am using Linq statement as per below to find student name by its ID. It works fine. However there are cases where there is no student with given ID. In those cases an error is thrown "Object reference not set to an instance of an object."
How to efficiently deal with this problem?
Dim Name As String = Students.FirstOrDefault(Function(Student) Student.ID = "NO00007").Name

If you are satisfied with Name being null if there is no matching student, you can use the null conditional operator for member access:
Dim Name As String = Students.FirstOrDefault(Function(Student) Student.ID = "NO00007")?.Name

As usually answer is "it depend" - it depend on how you will use result you will get
If you want get some "default"/empty string instead of name when collection doesn't contain item
Dim result = Students.Where(Function(student) student.ID = "NO00007").
Select(Function(student) student.Name).
DefaultIfEmpty(String.Empty).
First()
Almost same approach if you want to get some "empty" object instead of null
Dim resultStudent = Students.Where(Function(student) student.ID = "NO00007").
DefaultIfEmpty(New Student With { .Name = "empty" }).
First()
From performance point of view approach above are same as FirstOrDefault - but provide little bid better readability(subjective of course)

Related

Defining an expression or code with lookup RS

I need to migrate a CR report to RS.
I have two Methods, that are basically two queries, one is called "Products" the other one is called "Volume".
Both these datasets have a field called ID.
The idea is to count ProductsID = VolumeID. Can I use a lookup as an expression inside RS that counts when lookup is not equal to Nothing? Or I have to do a code to do that?
EDIT:
Let me add more information.
Crystal Report is managing these in the Data Layer of the web app like this:
DataRow drVol = vols.Rows.Find(new Object[] { id, idEzd });
if (drVol != null)
{
if (drVol["Volume"] != System.DBNull.Value)
cRow.Volume = (isNormalReport ? Convert.ToDecimal(drVol["Volume"]) : Convert.ToDecimal(drVol["Volume"]));
else
cRow.Volume = 0;
dset.Compradores.Rows.Add(cRow);
}
So in this case I verified that RS is giving me an X amount of rows while CR is giving me another amount of rows.
The Idea is to duplicate this on an expression or VB code inside RS.
As you can see, we have to filter the drVol != null, RS is bringing all the rows.
I know a Lookup function can be used in this case as:
Lookup(Fields!id.Value & Fields!idEzd.Value, Fields!id.Value & Fields!idEzd.Value,Fields!Givemethisfield.Value,"Dataset")
But can I use this Lookup expression inside a code to count?
The counter should be something like this (Then I should add the lookup or an if that equals that vlookup, can the code see the two datasets?):
Dim count=0 as integer
Public Function Counter() as Integer
count = count + 1
return count
End Function
Public Function GetCounter () as integer
return count
End Function
Then create a Calculated Field for example "Counter" with the expression
=Code.Counter()
And then make the sum of that calculated field:
=Sum(Fields!Counter.Value)
But is not working, not even the counter, is giving me 0.
Sorry if I made a mistake in the Visual Basic code, I don't program in Visual.
EDIT2:
I saw some workaround on MSDN, something like:
Lookup(Fields!id.Value & Fields!idEzd.Value, Fields!id.Value & Fields!idEzd.Value,Fields!Givemethisfield.Value,"Dataset").Lenght
It makes sense as a lookup is an Array.
The problem is, either if I choose one scope or the other, I still have the problem that some fields can't be seen for example if the fields id and idezd are on Dataset1 and Givemethisfield is on Dataset2, it will either not see the id,idEzd or Givemethisfield.

Entity Framework: Lazyloading appears to be off despite explicitly turning it on?

It would appear that my model first EF set up is not lazy loading related table records despite explicitly turning it on (which I understand I should not have to do since it's model first).
Code follows:
Using db As New Entity()
db.Configuration.LazyLoadingEnabled = True
Dim objectList as List(Of tableName) = _
db.tableName.Include("relatedTableName") _
.Where(Function(x) x.col1 = someValue) _
.OrderBy(Function(x) x.col2).ThenBy(Function(x) x.col3).ToList()
int testVal = 0
For Each item As tableName In objectList
testValue = item.relatedTableName.idColumn
Next
End Using
I get a System.NullReferenceException: Object reference not set to an instance of an object. error on this line:
testValue = item.relatedTableName.idColumn
In fact, item.relatedTableName doesn't have a value either. I have verified that I should be getting records back by writing an inner join statement in SQL.
What's going on here?
Apparently, the navigation property from a nullable field to the related table when there is more than 1 foreign key between the two tables will do this if you use the wrong navigation property.
That is to say that navigation properties relatedTableName and relatedtableName1 need to be used according to the data you want. If the first one points to a nullable street address column and the second one points to a non-nullable zip code column, point to the right one and expect a possible null object and null column.

LinQ: join on nullable property with value null

I have a list of objects, with a property customerId which is a nullable System.Guid property.
I also have a list of id's of type System.Guid, I also added a Guid.Empty value to this list.
I try to do a join on both, but the objects with empty guids aren't returned.
Dim dos = (From d In documents Join c In allowedCustomers On c Equals If(d.CustomerGuid = Nothing, System.Guid.Empty, d.CustomerGuid) Select d).Skip(10 * (pageNr - 1)).Take(10).ToList
What is wrong? Is there another way to do this in a better way?
You are using d.CustomerGuid = Nothing but you have to use d.CustomerGuid Is Nothing.
Try this approach which uses the VB.NET's null-coalescing operator.
Dim query = From doc In documents
Join custID In allowedCustomers
On If(doc.CustomerGuid, Guid.Empty) Equals custID
Skip 10 * (pageNr - 1)
Take 10
Select doc
Dim docList = query.ToList()
Note that you can increase readability with multiple lines, also, VB.NET's query syntax is powerful than C#, so you can use Skip and Take in the query.

How to get element from list A and list B using LINQ

How to get element from list A and list B using LINQ EVEN if list B is empty (will still return element of list A but elements of list B will be empty)
The idea is to be able to recreate a single anonymous object based on elements of list A and B.
From elemListA In data.ListA_
From elemListB In elemListA.ListB _
Select New With { _
.ElementA = elemListA.ElementA, _
.ElementB = elemListA.ElementB, _
.ElementC = elemListB.ElementA, _
.elementD = elemListB.ElementB, _
}).ToList()
The problem is that it will crash if ListB is empty.. and another problem is if i put a where it will not include the elements of ListA because they are filtered out by the where clause and i want to have them.
I would do a join but the problem is there no relation between the two object.. except an element from ListA have a ListB.
It is surprisingly tough to get an outer join effect when no join is possible. Basically, I can see two approaches:
Replace elemListA.ListB by an array with one empty (Nothing) element when ListB is null.
Dim array(0) as Nullable(of ElementB)
...
From elemListB In If(elemListA.ListB, array)
Use Union: first query the ListA objects that have a ListB and union with the object that haven't. In both queries you must create exactly the same anonymous types, so in the second part you must put .ElementB = emptyB where emptyB was declared by Dim emptyB As ElementB = Nothing.
Sounds like what you're describing is a left outer join. Microsoft wrote a tutorial on doing this with LINQ.
Specifically addressing your question, you need to check for a null value. In their example, Microsoft uses a ternary operator to return an empty string if the value is null.
var query = from person in people
join pet in pets on person equals pet.Owner into gj
from subpet in gj.DefaultIfEmpty()
select new { person.FirstName, PetName = (subpet == null ? String.Empty : subpet.Name) };

LINQ to Entities .contains is ignoring results with NULL

I am new to the Entity Framework, and am struggling with what I hope is a basic problem. My code is here:
Dim accounts As List(Of STUDENT) =
(From a In SA.STUDENTs
Where (a.MATRIC_NO.Contains(matric) And a.FIRST_NAME.Contains(firstName) And a.MIDDLE_NAMES.Contains(middleName) And a.SURNAME.Contains(lastName) And a.PREFERRED_NAME.Contains(preferredName))
Select a).ToList
The query runs fine, until one of the search fields is NULL in the database. If, for instance, a matric number is entered in the seach interface but middle name is left blank, the query will not return any records if middle name is NULL in the database. If middle name is a blank space in the database then it will return the record.
Can anyone offer any pointers?
Many thanks!
You can add an extra check in your query. For example:
public function filterList(IEnumerable list, string name)
{
var filtered_list = list.Where(x=> x.Name.Contains(name) || string.IsNullorWhitespace(name)).ToList();
return filtered_list;
}
So you can see, if the name variable is empty, all elements will return true, so all elements will be return (no real filter applied).
So basically, you can change all filters from
something.Contains(anotherthing)
to
something.Contains(anotherthing) || string.IsnullOrWhitespace(anotherthing)
(From a In SA.STUDENTs
Where isnull(a.MATRIC_NO.Contains(matric) And a.FIRST_NAME.Contains(firstName) And a.MIDDLE_NAMES.Contains(middleName) And a.SURNAME.Contains(lastName) And a.PREFERRED_NAME.Contains(preferredName))
Select a).ToList
Like this `:select * from tbl where statusid = isnull(#statusid,statusid)
try like this ..
Dim get_rmf_2 = From rmf In t_rmf _
Where Not IsDBNull(rmf!NIVP) AndAlso rmf!NIVP = nivp_rap
this is in VB I think this is works fine
I managed to solve this using a different approach. If there was no value entered for a particular field, leave it out the query. I accomplished this using predicates, as below:
'create the base query
Dim accounts =
(From a In SA.STUDENTs
Select a)
'create predicates for each condition required in the query
If matric <> "" Then
accounts = accounts.Where(Function(m) m.MATRIC_NO.Contains(matric))
End If
If firstName <> "" Then
accounts = accounts.Where(Function(f) f.FIRST_NAME.Contains(firstName))
End If
If middleName <> "" Then
accounts = accounts.Where(Function(mn) mn.MIDDLE_NAMES.Contains(middleName))
End If
If lastName <> "" Then
accounts = accounts.Where(Function(l) l.SURNAME.Contains(lastName))
End If
If preferredName <> "" Then
accounts = accounts.Where(Function(p) p.PREFERRED_NAME.Contains(preferredName))
End If
'execute the query
Dim accountlist = accounts.ToList
'return the results
Return accountlist
If anyone can see anything wrong with this, or any gotchas that I'm unaware of, please let me know! I'm very new to LINQ to Entities, and LINQ in general!