Linq SubmitChanges does not work - vb.net

I have some code like this:
Function GetTypeFromTableName(ByVal _TableName As String, ByVal _DataContext As DataContext)
Dim Mytype As Type = (From t In _DataContext.Mapping.GetTables Where t.TableName = "dbo." + _TableName Select t.RowType.Type).SingleOrDefault
Return Mytype
End Function
Dim DBA As New LINQDataContext
_TBLName="City"
TableType = GetTypeFromTableName(_TBLName, DBA)
CallByName(obj, "Code", CallType.Set,1)
Dim Equery = From T In DBA.GetTable(TableType) Select T
Equery = Equery.Where(Function(Oj1) Oj1 Is obj)
Dim oopp = From t In Equery Select CallByName(t, "CName", CallType.Get, Nothing)
oopp.ToList.Item(0) = Txt_Name.Text
DBA.SubmitChanges()
SubmitChanges do not work. What is wrong?

It looks like to me that you are selecting out a list of anonymous types, then changing the value in the list of anonymous types not in the matching object in the table. Since you haven't updated the table object itself, SubmitChanges has nothing to do.
Try changing it to the following
Dim matchingObj = Equery.Where( Function(Oj1) Oj1 Is obj )
.SingleOrDefault();
Then set the property value.
CallByName( matchingObj, "CName", CallType.Set, Txt_Name.Text );
Then submit your changes.
Note: I read VB ok, but I don't write it so well. You may need to fix up my syntax. You might also want to make sure that there is a matching object before you attempt to set it's property.

This is old but thought i will come and clear this up.
Whenever your update or Submitchanges fails try puttin InsertOnSubmit() statment. This statment will give you detailed error.
in my case I had very simple code.
var single = dataContext.MySysTables.FirstOrDefault();
single.DispatchIdIndex ++;
single.ModifyDate = DateTime.Now;
dataContext.SubmitChanges();
This was not being updated. When I put a InsertOnSubmit(single) line than it gave me error that "data can not be inserted because table does not have Primary key". This was my test table to i didnt have primary key. Once I added a new column and made a primary key than everything worked fine.
peace

Related

How can i resolve ExecucuteNonQuery throwing exception Incorrect syntex near '?'

Dim StrSql = "update student set id=?"
Updated (StrSql,15)
Public Function Updated (ByVal strSql As String, ByVal ParamArray Parameters As String ())
For Each x In Parameters
cmd.Parameters.AddWithValue("?",x)
Next
cmd.ExecuteNonQuery()
End Function
You didn't leave us much to go on; as jmcilhinney points out, you need to add more detail to future questions. For example in this one you have code there that doesn't compile at all, doesnt mention the types of any variable, you don't give the name of the database...
...I'm fairly sure that "Incorrect syntax near" is a SQL Server thing, in which case you need to remember that it (re)uses named parameters, unlike e.g. Access which uses positional ones:
SQL Server:
strSql = "SELECT * FROM person WHERE firstname = #name OR lastname = #name"
...Parameters.AddWithValue("#name", "Lee")
Access:
strSql = "SELECT * FROM person WHERE firstname = ? OR lastname = ?"
...Parameters.AddWithValue("anythingdoesntmatterwillbeignored", "Lee")
...Parameters.AddWithValue("anythingdoesntmatterwillbeignoredalso", "Lee")
This does mean your function will need to get a bit more intelligent; perhaps pass a ParamArray of KeyValuePair(Of String, Object)
Or perhaps you should stop doing this way right now, and switch to using Dapper. Dapper takes your query, applies your parameters and returns you objects if you ask for them:
Using connection as New SqlConnection(...)
Dim p as List(Of Person) = Await connection.QueryAsync(Of Person)( _
"SELECT * FROM person WHERE name = #name", _
New With { .name = "John" } _
)
' use your list of Person objects
End Using
Yep, all that adding parameters BS, and executing the reader, and converting the results to a Person.. Dapper does it all. Nonquery are done like connection.ExecuteAsync("UPDATE person SET name=#n, age=#a WHERE id=#id", New With{ .n="john", .a=27, .id=123 })
http://dapper-tutorial.net
Please turn on Option Strict. This is a 2 part process. First for the current project - In Solution Explorer double click My Project. Choose Compile on the left. In the Option Strict drop-down select ON. Second for future projects - Go to the Tools Menu -> Options -> Projects and Solutions -> VB Defaults. In the Option Strict drop-down select ON. This will save you from bugs at runtime.
Updated(StrSql, 15)
Your Updated Function calls for a String array. 15 is not a string array.
Functions need a datatype for the return.
cmd.Parameters.AddWithValue("?", X)
cmd is not declared.
You can't possible get the error you mention with the above code. It will not even compile, let alone run and produce an error.
It is not very helpful to write a Function that is trying to be generic but is actually very limited.
Let us start with your Update statement.
Dim StrSql = "update student set id=?"
The statement you provided will update every id in the student table to 15. Is that what you intended to do? ID fields are rarely changed. They are meant to uniquely identify a record. Often, they are auto-number fields. An Update command would use an ID field to identify which record to update.
Don't use .AddWithValue. See http://www.dbdelta.com/addwithvalue-is-evil/
and
https://blogs.msmvps.com/jcoehoorn/blog/2014/05/12/can-we-stop-using-addwithvalue-already/
and another one:
https://dba.stackexchange.com/questions/195937/addwithvalue-performance-and-plan-cache-implications
Here is another
https://andrevdm.blogspot.com/2010/12/parameterised-queriesdont-use.html
Since you didn't tell us what database you are using I guessed it was Access because of the question mark. If it is another database change the connection, command and dbType types.
Using...End Using block ensures you connection and command are closed and disposed even if there is an error.
Private ConStr As String = "Your Connection String"
Public Function Updated(StudentNickname As String, StudentID As Integer) As Integer
Dim RetVal As Integer
Using cn As New OleDbConnection(ConStr),
cmd As New OleDbCommand("Update student set NickName = #NickName Where StudentID = #ID", cn)
cmd.Parameters.Add("#NickName", OleDbType.VarChar, 100).Value = StudentNickname
cmd.Parameters.Add("#ID", OleDbType.Integer).Value = StudentID
cn.Open()
RetVal = cmd.ExecuteNonQuery
End Using
Return RetVal
End Function
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim RowsUpdated = Updated("Jim", 15)
Dim message As String
If RowsUpdated = 1 Then
message = "Success"
Else
message = "Failure"
End If
MessageBox.Show(message)
End Sub
This code keeps your database code separated from user interface code.

vba function which returns more than one value and so can be called in sql

I'm new to VBA and i need help.
I want to create vba function which takes table name as input, and distinct specific field from that table. I created function, and it works when i run it in vba immediate window (when i use debug.print command to display results). But when i call this function in sql, instead whole field values, it returns just last one. I'm not good at vba syntax so i need help to understand. Does function can return more than one value? If can, how, and if not what else to use? Here's my code:
Public Function TableInfo(tabela As String)
Dim db As Database
Dim rec As Recordset
Dim polje1 As Field, polje2 As Field
Dim sifMat As Field, pogon As Field, tipVred As Field
Set db = CurrentDb()
Set rec = db.OpenRecordset(tabela)
Set sifMat = rec.Fields("Field1")
Set pogon = rec.Fields("Field2")
Set tipVred = rec.Fields("Field3")
For Each polje1 In rec.Fields
For Each polje2 In rec.Fields
TableInfo = pogon.Value
rec.MoveNext
Next
Next
End Function
Any help is appreciated.
The problem is with this line probably:
TableInfo = pogon.Value
It runs inside the loop and returns the last value of the loop.
Instead of returning one value TableInfo, you may try to return something similar to a Collection or an Array.
Inside the loop, append values in the Collection and after the loop, return the Collection back from the function.
Edit:
I have re-written the code shared by you:
Public Function TableInfo(tabela As String) as String()
Dim db As Database
Dim rec As Recordset
Dim polje1 As Field, polje2 As Field
Dim sifMat As Field, pogon As Field, tipVred As Field
Dim returnValue() As String
Dim i as Integer
Set db = CurrentDb()
Set rec = db.OpenRecordset(tabela)
Set sifMat = rec.Fields("Field1")
Set pogon = rec.Fields("Field2")
Set tipVred = rec.Fields("Field3")
' I am not going to modify this but I think we can do away with two For Each loops.
' Just iterate over rec like
' For Each r In rec -> please use proper naming conventions and best practices
' and access each field as r("Field1") and r("Field2")
For Each polje1 In rec.Fields
For Each polje2 In rec.Fields
returnValue(i) = pogon.Value
i = i + 1
rec.MoveNext
Next
Next
TableInfo = returnValue
End Function
Please note: I have not tested this code but I assume this should work for you. Also, I have assumed that you want to return String() array. Please change the data type if you want to return some other type.
When you call the array (as posted in theghostofc's answer), you will need to do something like this:
Dim TableInfo() As String
For i = LBound(TableInfo) To UBound(TableInfo)
YourValue = TableInfo(i)
... Process some code that uses YourValue
Next i
If you're not looping through your array, you're not going to get each individual value out of it.

Linq-to-SQL Database Update Fails

Very simple update. It simply fails, no error, no change gets made to the database.
Dim db As New BarClassesDataContext
Dim foo = (From a In db.articles Where a.id = 14 Select a).Single
Response.Write("<h3>" & foo.title & "</h3>")
foo.title = "This is my new, updated title for article ID #14"
db.SubmitChanges()
Here is the relevent portion of my article class. Also, this is a web form so I have no console. Is there another way to view the T-SQL output?
<Table(Name:="dbo.article")> _
Partial Public Class article
Private _id As Integer
Private _issueid As Integer
Private _dateadded As Date
Private _title As String
Private _titlelink As String
Private _description As String
Private _image As String
Private _imagelink As String
Private _type As Integer
Public Sub New()
MyBase.New
End Sub
<Column(Storage:="_id", AutoSync:=AutoSync.Always, DbType:="Int NOT NULL IDENTITY", IsDbGenerated:=true)> _
Public Property id() As Integer
Get
Return Me._id
End Get
Set
If ((Me._id = value) _
= false) Then
Me._id = value
End If
End Set
End Property
If you have any invalid fields definitions you may have an issue where 0=1 is added to the WHERE clause. Check that all of your non-nullable fields are set. (I fought with this for about two hours one night while watching the SQL profiler add the extra 0=1 for no reason.)
Post on Social MSDN
Another post about this issue
(If I can find the issue on connect.microsoft.com I will post it as well)
At first glance, I would say one (but not the main) problem is '='. I think it needs to be:
Dim foo = (From a In db.articles Where a.id == 14 Select a).Single
The main problem I see is the lack of an UpdatetOnSubmit() statement. How does L2S know you want to do an Update?
Try
db.Articles.UpdateOnSubmit(foo);
db.SubmitChanges();
or something close to this.
My suspicion is that you don't have a properly defined primary key in your database and/or in your System.Data.Linq.Mapping attributes. Show us the Article class - that will likely be where your problem is. Make sure you have an IDENTITY field in your database, and be sure your linqed up class has got IsPrimaryKey:=True and IsDbGenerated:=True in the <Column> attribute.
Also, it would be wise to set the .Log property on your DataContext to see what SQL is being executed. I like the debug window logger technique, which I have mentioned before here: DataContext SubmitChanges in LINQ

LINQ VB.net Return Single Type of Object Invalid Cast

Ok, just needing a 2nd set of eyes looking at this to make sure the error isn't something else other than my LINQ code here. Here's the function class itself:
Public Function GetJacketByPolicyID(ByVal jacketID As Int32) As tblPolicy
Dim db As New DEVDataContext()
Dim j As tblPolicy = db.tblPolicies.Single(Function(p) p.policyNumber = jacketID)
Return j
End Function
and here is the code which calls this class function in the web control form itself:
Dim p As tblPolicy
Dim j As New Jackets()
p = j.GetJacketByPolicyID(3000050)
For some reason it's flagging the 2nd line in the GetJacketByPolicyID function saying the specified cast is not valid. So I'm guessing it's something I'm doing wrong. I'm sure the tblPolicy/tblPolicies class works right since I can create a new instance of a tblPolicy and set a few variables by hand and return it, so that's not it. I've also checked the datarow I'm fetching and there's no null values in the record, so that shouldn't be it either.Any help much appreciated.
This would seem to get what you are looking for. Not sure why you are passing in a function for a simple query like this.
Public Function GetJacketByPolicyID(ByVal jacketID As Int32) As tblPolicy
Dim _jacket as tblPolicy
Using _db As New DEVDataContext()
_jacket = (From _j In db.tblPolicies Where _j.policyNumber.Equals(jacketID) Select _j).Single()
End Using
Return _jacket
End Function

An SqlParameter with ParameterName is not contained?

I have a problem with something I have done many times but this time it just doesn't work.
This is what what I am trying to do (in Visual Studio 2003 and VB.NET)
Earlier in the code:
Private SaveCustomerInformationCommand As System.Data.SqlClient.SqlCommand
Then this in a setup process:
SaveCustomerInformationCommand = New System.Data.SqlClient.SqlCommand("spSaveCustomerInformation")
SaveCustomerInformationCommand.CommandType = Data.CommandType.StoredProcedure
Dim custIdParameter As System.Data.SqlClient.SqlParameter = SaveCustomerInformationCommand.CreateParameter()
custIdParameter.ParameterName = "#CustId"
custIdParameter.SqlDbType = Data.SqlDbType.Int
custIdParameter.Direction = Data.ParameterDirection.Input
SaveCustomerInformationCommand.Parameters.Add(custIdParameter)
And then later:
SaveCustomerInformationCommand.Parameters.Item("#CustId").Value = myValue
And I get this:
System.IndexOutOfRangeException: An SqlParameter with ParameterName '#CustId' is not contained by this SqlParameterCollection.
Any ideas/solutions?
AFAIK, the "#" is not technically part of the name of the parameter... rather it's what you put into your T-SQL to denote that a parameter name is coming afterwards. So I think you'll want to refer to it like this instead (with no "#") :
SaveCustomerInformationCommand.Parameters.Item("CustId").Value = myValue
You could also try the same thing when you initially insert the parameter name-- although since you're not getting an error there, I'd suspect the accessor call is to blame, not the inserter call.