Handling Null reference exception - visual-studio-2010

I am trying to insert following into my code.
Public ReadOnly Property SelectedCustomer() As Customer
Get
If lstCustomers.SelectedIndex <> -1 Then
' Return the selected customer
Return CType(objCustomers(lstCustomers.SelectedIndex), Customer)
End If
End Get
End Property
But while saving following warning occures.
Property 'SelectedCustomer' doesn't return a value on all code paths. A null reference exception could occur at run time when the result is used.
How to resolve this? Any help?

What happens when lstCustomer.SelectedIndex = -1?
You are currently not returning anything. Which is why you are getting the not return on all paths message.
A simple solution
Public ReadOnly Property SelectedCustomer() As Customer
Get
If lstCustomers.SelectedIndex <> -1 Then
' Return the selected customer
Return CType(objCustomers(lstCustomers.SelectedIndex), Customer)
End If
Return Nothing
End Get
End Property
The problem with this is you still have to handle for Nothing when reading this property.
You could also return a new instance of Customer, but once again, you need to handle that on the other end.

Related

No row can be added to a DataGridView control that does not have columns. Columns must be added first. in VB.net

I have been encountering an error in my VB.Net code that says "No row can be added to a DataGridView control that does not have columns. Columns must be added first.". When I was trying to code a live search on a datagridview1. Please help me.
Here is the code for the datagrid live search that encounters an error:
Private Sub txt_search_TextChanged(sender As Object, e As EventArgs) Handles txt_search.TextChanged
DataGridView1.Rows.Clear()
'' Searching via room number or category id, ie room type
Try
conn.Open()
Dim cmd As New MySqlCommand("SELECT r.id, r.room_no, c.name, r.description, r.price FROM categories c JOIN rooms r ON c.id = r.category_id WHERE room_no LIKE '%" & txt_search.Text & "%' or name LIKE '%" & txt_search.Text & "%'", conn)
dr = cmd.ExecuteReader
While dr.Read
DataGridView1.Rows.Add(dr.Item("ID"), dr.Item("room_no"), dr.Item("name"), dr.Item("description"), dr.Item("price"))
End While
dr.Dispose()
Catch ex As Exception
MsgBox(ex.Message)
End Try
conn.Close()
End Sub
I would do a few things differently.
You should not declare your connection at the class level, instead create a new connection and dispose immediately when done.
Same with the DataRow.
I personally wouldn't like to see results immediately after typing a character in a searchbox. If I have a typo, then want to erase it and fix it, I need to wait for the typo result, then see the fixed result. We'll use a timer to create this delay.
Which brings me to the other issue, which is that you are hitting your database on the UI thread, so add that to the last item, your end user is experiencing a UI freeze while waiting for results with each keypress. We will query off the UI and invoke the update back when done.
Don't put textbox Text directly into a query or you will be opened up to sql injection issues. We will use parameters
(Oh, and I haven't even arrived at your question yet!)
You can simply databind the result to the grid instead of trying to add rows. You can only add rows if the grid has predefined rows with a template for new rows. You can do that but this locks your UI into a particular design so if you want to change the query later, you will also need to fix the UI. Too tightly coupled. We'll use a class to define the data. You will get these if you use an ORM which is vastly superior to using a DataReader, but you don't so I made one.
Let's see...
Private Class Result
Public Sub New(iD As Integer, room_no As String, name As String, description As String, price As Decimal)
Me.ID = iD
Me.Room_no = room_no
Me.Name = name
Me.Description = description
Me.Price = price
End Sub
' Update data types according to your actual database types
Public Property ID As Integer
Public Property Room_no As String
Public Property Name As String
Public Property Description As String
Public Property Price As Decimal
End Class
You will want to make a timer to tick when you want to hit the database. Also record the current state of the textbox at this time. This is all you do in the TextChanged event handler
Private queryTimer As New System.Threading.Timer(AddressOf queryCallback)
Private queryTerm As String
Private Sub txt_search_TextChanged(sender As Object, e As EventArgs) Handles txt_search.TextChanged
queryTerm = txt_search.Text.Trim() ' do you want to trim whitespace?
' Execute search 500ms later.
' If multiple keystrokes are pressed quickly,
' previous timer schedules are cancelled and only the last happens.
queryTimer.Change(500, -1)
End Sub
This is the timer callback, which runs off the UI and invokes the UI update when it's done
Private Sub queryCallback(state As Object)
' This routine is called on a background thread, off the UI
Dim results As New List(Of Result)()
Using conn As New MySqlConnection("connection string")
conn.Open()
' build command with parameter
Using cmd As New MySqlCommand(
$"SELECT r.id, r.room_no, c.name, r.description, r.price
FROM categories c
JOIN rooms r ON c.id = r.category_id
WHERE room_no LIKE '%#search%'
or name LIKE '%#search%'", conn)
cmd.Parameters.AddWithValue("#search", queryTerm)
Using dr = cmd.ExecuteReader()
While dr.Read()
' Update conversions according to actual data types
' here as well as in the class I provided.
results.Add(New Result(
Convert.ToInt32(dr("id")),
dr("room_no").ToString(),
dr("name").ToString(),
dr("description").ToString(),
Convert.ToDecimal(dr("price"))))
End While
End Using
End Using
End Using
' Can't update the UI from a background thread, so this call is invoked
DataGridView1.Invoke(
Sub()
DataGridView1.DataSource = Nothing
DataGridView1.DataSource = results
End Sub)
End Sub
Additional information is in remarks in the code provided

OptionSetValueCollection not taking a null value. Throws Generic SQL error when setting up the value to null

I'm creating a new record in CRM plugin(by reading the data from a related record) and the data that I'm passing may / may not contain "OptionSetValueCollection". Whenever the value for the OptionSetValueCollection is null the IOrganization.Create is throwing a Generic SQL exception.
Currently I'm checking the submitted value for null and when not null I'm not submitting a value for the created object.
My question is why does OptionSetValueCollection not taking null? Is this a platform issue?
I've also tried creating a List<OptionSetValue> object and adding the incoming OptionSetValues from the OptionSetValueCollection and then passing it to the target attribute, tried passing in null and also used the null-coalescing operator all with no luck.
//Earlybound code
Account account = new Account(){
Name = newBrand,
new_accounttype = new OptionSetValue((int)new_AccountType.Brand),
TerritoryId = siteRequestRecord.new_territoryid,
new_category1 = siteRequestRecord.new_category1 ?? null,
};
if (category2 != null)
{
account.new_category2 = siteRequestRecord.new_category2;
}
service.Create(account);
Seems to be a long outstanding issue.
There is a bug related to multiselect optionset - if you set it to null during creation that will trigger an error. But the same code that sets field to null works fine during update.
So if you set it to null during Create just don't set field value and as a result you'll get blank value of a field.
If I understand you want to set Optionset to null. use below code it shall work and set null for your optionset
new_accounttype = null;

Validation not working on click of submit button but after submit proccess does, why so?

I have a validation on a text field. After a submit page button is pressed, I want the validations to check the code below and return a plsql text if it fails. Once the validation returns null(as in no issue) an after submit proccess should occur. The issue is, the after submit proccess still occurs and the validations are only producing >> ELSE RETURN 'Invalid email address'; rather than any of the other e.g. invalid email address if there's no text in the field. Oh an also I have a server side condition on the field to work when the button is clicked.
Help would be really appreciated. Thank you.
Edit: thanks for editing. I did have the BEGIN in it before I just forgot to add it to this post. The issue is still ongoing.
BEGIN
IF (INSTR(:P101_NEW_2, '#gmail.com') > 0) THEN RETURN NULL;
ELSIF (INSTR(:P101_NEW_2,'#hotmail.com) > 0) THEN RETURN NULL;
ELSIF (INSTR(:P101_NEW_2,'#yahoo.com') > 0)THEN RETURN NULL;
ELSIF (:P101_NEW_2 = NULL) THEN RETURN 'Input Email Address';
ELSIF (INSTR(:P101_NEW_2, '#gmail.com') < 1) OR (INSTR(:P101_NEW_2,'#hotmail.com') < 1) OR (INSTR(:P101_NEW_2,'#gmail.com') < 1) THEN RETURN 'Input Email Address';
ELSE RETURN 'Invalid email address';
END IF;
COMMIT;
END;
I believe I've solved it. It's validation with PL/SQL Function (returning text). I did not create a function as you can see from the above code. I'll create a function and include that code and let you know how I get on.
Email address validations typically validate the format, but that's up to you.
not REGEXP_LIKE(:P1_EMAIL, '^[^.]([a-zA-Z0-9_''\+\.\-]+)[^.]#[a-zA-Z0-9_\-]+(\.[a-zA-Z0-9\-]+)*(\.[a-zA-Z]{2,})$')
Validations aim for true/null, so if there is a problem then depending on the type it will return false or a message to display.
If you compare :P1_EMAIL = null, it will always return false. Nothing is ever = null. It should be :P1_EMAIL is null
Your penultimate condition might as well be :P1_EMAIL is not null, since you've checked content and null-ness.
You only need begin/end if you have declare or exception sections.
And you will rarely need a commit in APEX.

Salesforce bulkify code - is this not already bulkified?

We have a class in salesforce that is called form a trigger. When using Apex Data Loader this trigger throws an error oppafterupdate: System.LimitException: Too many SOQL queries: 101
I commented out a line of code that calls the following static method in a class we wrote and there are no more errors with respect to the governing limit. So I can verify the method below is the culprit.
I'm new to this, but I know that Apex code should be bulkified, and DML (and SOQL) statements should not be used inside of loops. What you want to do is put objects in a collection and use DML statements against the collection.
So I modified the method below; I declared a list, I added Task objects to the list, and I ran a DML statement on the list. I commented out the update statement inside the loop.
//close all tasks linked to an opty or lead
public static void closeTasks(string sId) {
List<Task> TasksToUpdate = new List<Task>{}; //added this
List<Task> t = [SELECT Id, Status, WhatId from Task WHERE WhatId =: sId]; //opty
if (t.isEmpty()==false) {
for (Task c: t) {
c.Status = 'Completed';
TasksToUpdate.add(c); //added this
//update c;
}
}
update TasksToUpdate; //Added this
}
Why am I still getting the above error when I run the code in our sandbox? I thought I took care of this issue but apparently there is something else here? Please help.. I need to be pointed in the right direction.
Thanks in advance for your assistance
You have "fixed" the update part but the code still fails on the too many SELECTs.
We would need to see your trigger's code but it seems to me you're calling your function in a loop in that trigger. So if say 200 Opportunities are updated, your function is called 200 times and in the function's body you have 1 SOQL... Call it more than 100 times and boom, headshot.
Try to modify the function to pass a collection of Ids:
Set<Id> ids = trigger.newMap().keyset();
betterCloseTasks(ids);
And the improved function could look like this:
public static void betterCloseTasks(Set<Id> ids){
List<Task> tasksToClose = [SELECT Id
FROM Task
WHERE WhatId IN :ids AND Status != 'Completed'];
if(!tasksToClose.isEmpty()){
for(Task t : tasksToClose){
t.Status = 'Completed';
}
update tasksToClose;
}
}
Now you have 1 SOQL and 1 update operation no matter whether you update 1 or hundreds of opportunities. It can still fail on some other limits like max 10000 updated records in one transaction but that's a battle for another day ;)

Subsonic 3 Newtonsoft JSON "Self referencing loop Exception"

Hi I been searching for my error but I can't find anything that help me. The problem is this. I been working with Subsonic 3, Newtonsoft Json and the linq way of write so I have this easy query:
var found = from client in newclients.All() where client.Period == "sometext" select client;
string periodoJSON = JsonConvert.SerializeObject(periodoFound); //this get "Self referencing loop Exception"
the problem is when I run this script I get the horrible exception "Self referening loop exception" in the JsonConvert line, subsonic have all the objects without any problem but if I do the following.
var found = from client in newclients.All() where client.Period == "sometext" select new client{client.Name, client.LastName, etc};
string periodoJSON = JsonConvert.SerializeObject(periodoFound);
I get the object serialize with a any problem with all the properties. I'm doing the last way because I have to finish my work but is any other way or solution for this problem, if not I will have to write all the properties every time I want to get a full table properties.
hope any can solve my problem o help me in the path for find a solution....
what I have is a really basic query with linq and I try the three values for JsonSerializerSettings and any work, again I'm working with subsonic 3 this not happend either with subsnoic 2 and I can make it work if I specify one by one the properties of the object in the linq query does any have any clue of what is happend, ANY more help would be great!!! If I put the value of Serialize my page get crazy and in a infinity loop state, if I decide for error simple doesn't work and Ignore nothing happen... some more information about this self referencia loop?
var u = usuario.SingleOrDefault(x => x.TipoUsuario == "A" || x.TipoUsuario == "W");
JsonSerializerSettings setting = new JsonSerializerSettings();
setting.ReferenceLoopHandling = ReferenceLoopHandling.Error; //.Serialize .Ignore
Page.ClientScript.RegisterClientScriptBlock(this.GetType(),"usuario", "var usuario=" + JsonConvert.SerializeObject(u, Formatting.None, setting) + ";");
Update ------
I code the following
string jsU = JsonConvert.SerializeObject(u,Formatting.None,new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.Objects, ReferenceLoopHandling = ReferenceLoopHandling.Ignore });
and is workign but the only thing wrongs is that in the json object comes all the information about the columns of subsonic 3 and a BIG chunk of text explain it... does any one know how to not SEND this part of the object??
Without knowing more about you object model it is hard to provide a definitive answer, but I would take a look at the ReferenceLoopHandling enum.
You're calling string SerializeObject(object value) on JsonConvert. Try the string SerializeObject(object value, Formatting formatting, JsonSerializerSettings settings) method instead. The JsonSerializerSettings settings parameter lets you set a bunch of things, including the ReferenceLoopHandling ReferenceLoopHandling { get; set; } property.
You can try these values:
public enum ReferenceLoopHandling
{
Error,
Ignore,
Serialize
}
Obviously, Error is the default and that's what you're getting. Perhaps one of the others will help.

Resources