Linq to SQL - Problem in Stored Procedure - linq-to-sql

I have storeProcesdure name called as prc_GetID, it's return value (ClientID)
Here thr proc Code:
Create PROCEDURE [dbo].[prc_GetID] (#ID VARCHAR(20))
AS
SET NOCOUNT ON;
SELECT ClientID FROM dbo.Clients WHERE [ID]=#ID
I use above STORED PROCEDURE with linq to sql, here's Code,
Public Class Form2
Dim dcClients As New dcDataContext(CNString)
Private Sub btnClick_Click(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles btnClick.Click
Dim CID = dcClients.prc_P(txtID.Text)
txtClientID.Text = CID.ReturnValue
End Sub
End Class
Here's My dcDataContext Code
<FunctionAttribute(Name:="prc_GetID")> _
Public Function prc_GetID(<Parameter(Name:="ID", DbType:="VarChar(20)")> _
ByVal ID As String) As ISingleResult(Of prc_GetIDResult)
Dim result As IExecuteResult = Me.ExecuteMethodCall(Me, _
CType(MethodInfo.GetCurrentMethod,MethodInfo), ID)
Return CType(result.ReturnValue,ISingleResult(Of prc_GetIDResult))
End Function
but it's return value 0 Why?,

Are you confusing the return value with the result set?

You probably should be examining CID.ClientID, not CID.ReturnValue. ReturnValue is the response code of the stored procedure, not the returned data you're looking to find. If you don't have a ClientID property you may need to remap your stored procedure to get the proper return type visible to your app.
Correction applied to account for multiple results (wasn't thinking):
Your stored procedure will return multiple records. Do you want the first record returned? If so and you will always have at least one row returned, try this:
txtClientID.Text = CID.First().ClientID.ToString()
In reality you need to think about your multiple records or no records returned and deal with it appropriately. Also, please don't continue to do your data access from within a form; it's good practice to create a library/business layer project to keep business logic out of your UI.

Related

Updating date in SQL/VB/Asp.Net

I'm pretty much a novice at all this. I know bits. Just trying to store a date in an SQL database. I've set it to 06/06/2015 temporarily in code below to see if I can get it to update but it updates it as 01/01/0001. When I suss it, The value I actually want to store is todays date plus 6 months. EG: if its 31/07/2015 today, I want it to store 31/01/2016. Can anyone help ? Much appreciated...
ASPX.VB
Protected Sub imgBtnDatechange_Click(sender As Object, e As ImageClickEventArgs) Handles imgBtn.Click
Dim acc As New accounts(Membership.GetUser().ProviderUserKey)
Dim adjustedDate as Date = "06/06/2015"
acc.UpdateVipEndDate(acc.accountID, acc.adjustedDate)
End Sub
ACCOUNTS.VB
Public Property adjustedDate As Date
Public Sub UpdateVipEndDate(ByVal accountID As Guid, ByVal adjustedDate As Date)
Dim DBConnect As New DBConn
Using db As DbConnection = DBConnect.Conn("DBConnectionString")
Dim cmd As SqlCommand = DBConnect.Command(db, "UpdateVipEndDate")
cmd.Parameters.Add(New SqlParameter("accountID", SqlDbType.UniqueIdentifier, ParameterDirection.Input)).Value = accountID
cmd.Parameters.Add(New SqlParameter("newadjustedDate", SqlDbType.Date, ParameterDirection.Input)).Value = adjustedDate
db.Open()
cmd.ExecuteNonQuery()
cmd.Dispose()
cmd = Nothing
db.Dispose()
db.Close()
End Using
End Sub
STORED PROCEDURE
CREATE PROCEDURE [UpdateVipEndDate]
#accountID uniqueidentifier,
#newadjustedDate date
AS
BEGIN
UPDATE tblAccounts SET [vipEndDate] = #newadjustedDate WHERE [accountID] = #accountID
END
You set a date here:
Dim adjustedDate as Date = "06/06/2015"
But you never use that variable anywhere. Instead, you're using a parameter on the acc object:
acc.UpdateVipEndDate(acc.accountID, acc.adjustedDate)
So, presumably, the acc.adjustedDate value is otherwise empty or some default MinDate value.
It seems like you're confusing a few things here...
If something is a Date, use it as a Date. Not as a String.
If the UpdateVipEndDate method is on the acc object, why do you need to pass it references to its own parameters? It should be able to access those values internally in the method.
I'm probably getting off point here, though. The simplest thing, it seems, would be to not use a local variable and use the object member that you use elsewhere:
acc.adjustedDate = "06/06/2015"

How to check if table exists in MySql db?

I have a VB6 application and I want to check if a table exists within a MySQL database on phpmyadmin. In reality the table is actually a view however it should act exactly as it's own table.
The code I currently have constantly returns false?
I think my problem might have to do with the variable cnDataStoreToVerify because when I try to print its Contents it only contains:
"Provider=MSDASQL.1;" ?
Help would be much appreciated!
Public Function TableExists(cnDataStoreToVerify As ADODB.Connection, strTableName as String) As Boolean
Dim recTemp As ADODB.Recordset
Set recTemp = cnDataStoreToVerify.OpenSchema(adSchemaTables, Array(Empty, Empty, StrTableName, Empty))
If Not recTemp.EOF Then
TableExists = True
End If
Exit_TableExists:
m_oADOUtils.CloseRecordsetADO recTemp
End Function

Comparing datatables / identify identical datatables

I am working with VB.net and mysql, I have a function which fills a datatable with mysql content then posts it (as appropriate) to a listview. This function is currently on a timer which activates every 5 seconds which unfortunately does horrible destruction to the drag-and-drop features of my software.
The solution: I have decided after filling the content to the listview to copy the content from the active datatable to another datatable for comparison, every time the data is taken from the mysql db have it save to a datatable and compare the two datatables - if they are not identical the software should run the function however if they are identical there is no reason to update the listview with the same exact data.
Public pendrun As New DataTable
Public postrun As New DataTable
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
con.ConnectionString = "server=localhost;" _
& "user id=user;" _
& "password=password;" _
& "database=DMT"
adptr = New MySqlDataAdapter("Select * from data", con)
Try
adptr.Fill(pendrun)
Catch err As Exception
Dim strError As String = "Exception: & err.ToString()"
End Try
if pendrun <> postrun then
ListView2.Items.Clear()
pendrun.Clear()
' commands to add
' pendrun datatable information
' to listview
postrun = pendrun 'to transfer data to the holding datatable
end if
the problem is
if pendrun <> postrun then
is not a valid way to compare datatables.
How do I identify if the datatables are identical (all rows and columns identical)
There's no built-in understanding of "identical" for types you've defined. You'll need to write that logic.
Essentially you need to build a function which accepts two DataTables as input, compares them in accordance with whatever business logic you define, and returns a Boolean indicating whether or not they pass that logic. Something like this:
Function TablesAreEqual(ByVal firstTable As DataTable, ByVal secondTable As DataTable) As Boolean
' Compare your tables, probably by looping through rows/values
Return areEqual
End Function
Then you'd use that function in your comparison:
If TablesAreEqual(pendrun, postrun) Then
Here is the resulting code I created to deal with this problem - thanks to David for the direction
Function TablesAreEqual(ByVal firstTable As DataTable, ByVal secondTable As DataTable) As Boolean
dim db1 As String = ""
dim db2 As String = ""
For rown As Integer = 0 To firstTable.Rows.Count - 1
For cown As Integer = 0 To firstTable.Columns.Count - 1
db1 = db1 & firstTable.Rows(rown).Item(cown)
Next
Next
For rown As Integer = 0 To secondTable.Rows.Count - 1
For cown As Integer = 0 To secondTable.Columns.Count - 1
db2 = db2 & secondTable.Rows(rown).Item(cown)
Next
Next
Return db1 = db2
End Function
If you want to use your pendrun and postrun datatables
try to serialize "writeXml" datatables and compare them.
Anyway i suggest you to think about a different approach instead of using a polling timer.
Better yet why not put in logic to not get new data if it has not changed.
Don't know about MySQL but MSSQL has Notification and TimeStamp
The columns should only change with a schema change.
First compare count and if not the same for sure there was a change.
If counts are the same then loop through the columns and compare.
As soon as one does not compare then done immediately return false.
On rows same thing. First test row count.
After that need to compare row by row and column by column.
Remember to sort the select statement so you would catch rows out of order.
And again as soon as one does not compare stop and return false.
Right with less code than you have in your answer
My inserts are C#
Function TablesAreEqual(ByVal firstTable As DataTable, ByVal secondTable As DataTable) As Boolean
if(firstTable.Rows.Count != secondTable.Rows.Count) return false;
if(firstTable.Columns.Count != secondTable.Columns.Count) return false;
For rown As Integer = 0 To firstTable.Rows.Count - 1
For cown As Integer = 0 To firstTable.Columns.Count - 1
if (firstTable.Rows(rown).Item(cown) != secondTable.Rows(rown).Item(cown)) return false;
Next
Next
return true;
End Function

Returning Multiple Values from a Custom Function

So, I've got a ValidateForm function that loops through a form to validate each control. I have a collection set up called ValData to capture different bits of info to be passed out of the function. This is working great.
However, I don't know how to access each item in ValData after the function returns. I can get one at a time like: ValidateForm().IsValid, but in order to get each item, I have to run the function again. I want to avoid this.
Is there a way to run the function once, but access the values of each item returned?
Depending upon your requirements (which are NOT clear in your question! ;-) ), you might consider using a Collection as the return from your function:
Private Function MyResultsFunction() As Collection
Dim output As Collection
Set output = New Collection
'Hydrate your collection with data by whatever means necessary:
With output
'Stupid example code:
.Add "Item1"
.Add "Item2"
.Add "Item3"
.Add "Item4"
End With
'Return a reference to the collection as the function output:
Set MyResultsFunction = output
End Function
As a simple, retarded test of the above:
Private Sub Form_Load()
'A variable to receive the results from your function:
Dim Results As Collection
'An iterator to loop through the results contained in the collection:
Dim CurrentItem As Variant
'For this example, a string to toss the results into to display in the
'MsgBox:
Dim output As String
'Use the local Collection defined above to access the reference returned by
'your function:
Set Results = MyResultsFunction
'Iterate through the collection and do something with the results
'per your project requirements:
For Each CurrentItem In Results
'This is stupid example code:
output = output & CurrentItem & vbCrLf
Next
'I am just displayng the results to show that it worked:
MsgBox output
'Clean up:
Set Results = Nothing
End Sub
Hope that heps!
Without seeing your code it's hard to say what exactly you are tyring to do, but here is one of several ways you can store results to query later.
Declare a public variable at the top of your module to represent the items from your ValData function. After you populate the array, you can access the items through a normal function.
You obviously could do more sophisticated things, especially if you use a collection object. You could even store a counter and create a GetNext() function. I hope this gives you a heads start.
Public Results(1 To 2) As String
Sub CreateTestArray()
Results(1) = "Foo"
Results(2) = "Bar"
End Sub
Function GetResult(ByVal i As Long) As String
If i <= UBound(Results) Then
GetResult = Results(i)
End If
End Function
Sub ProofOfConcept()
MsgBox GetResult(2) ' will show "Bar"
End Sub

grab linq to sql record by primarykey without knowing its type

how can i grab a record (and eventually delete it) using linq2sql without knowing the type at compile time?
so far i've got
Sub Delete(ByVal RecordType As String, ByVal ID As Integer)
Dim dummy = Activator.CreateInstance(MyAssembly, RecordType).Unwrap
Dim tbl = GetTable(dummy.GetType)
tbl.DeleteOnSubmit(dummy)
End Sub
but of course the dummy is not an actual record, its just a dummy
i don't want to use direct sql (or executecommand) as there's business logic going on at deletion in the datacontext partial class
can this be done somehow?
thank you very much!
EDIT
in response to striplinwarior, i edited my code to:
Sub Delete(ByVal RecordType As ObjectType, ByVal ID As Integer)
Dim dummy = Activator.CreateInstance(ObjectType.Account.GetType.Assembly.FullName, RecordType.ToString).Unwrap
SetObjProperty(dummy, PrimaryKeyField(RecordType), ID)
Dim tbl = GetTable(dummy.GetType)
tbl.Attach(dummy)
tbl.DeleteOnSubmit(dummy)
SubmitChanges()
End Sub
this does fire off the deletion code correclty, but also seems to try to add the record first to the db, as i get a sqlexception that some "not null" fields are empty, which i guess is true about the dummy record, as the only thing this has is the primarykey, else is all empty. so i tried the other code u posted (something i anyways always wanted to have) and that works excellent!
hers my current code:
Function LoadRecord(ByVal RecordType As String, ByVal RecordID As Integer) As Object
Dim dummy = Activator.CreateInstance(AssemblyName, RecordType).Unwrap
Dim rowType = dummy.GetType
Dim eParam = Expression.Parameter(rowType, "e")
Dim idm = rowType.GetProperty(PrimaryKeyField(RecordType))
Dim lambda = Expression.Lambda(Expression.Equal(Expression.MakeMemberAccess(eParam, idm), Expression.Constant(RecordID)), eParam)
Dim firstMethod = GetType(Queryable).GetMethods().[Single](Function(m) m.Name = "Single" AndAlso m.GetParameters().Count() = 2).MakeGenericMethod(rowType)
Dim tbl = GetTable(rowType)
Dim obj = firstMethod.Invoke(Nothing, New Object() {tbl, lambda})
Return obj
End Function
Sub Delete(ByVal RecordType As String, ByVal RecordID As Integer)
Dim obj = LoadRecord(RecordType, RecordID)
Dim tbl = GetTable(obj.GetType)
tbl.DeleteOnSubmit(obj)
SubmitChanges()
End Sub
Thank You
The only way I can think of is to use the model information from your database mapping to figure out which member represents the primary key:
Dim primaryKey = (From t In db.Mapping.GetTables() _
Where t.RowType.Type = tableType _
Let keyMember = (From dm In t.RowType.DataMembers where dm.IsPrimaryKey).FirstOrDefault() _
Select keyMember.Member.Name).First()
(I'm using LinqPad here: I assume typical LINQ to SQL models have this mapping information available.)
Then use reflection to set the value of that key member on the dummy item you've created. After that, you need to attach the dummy to the table before trying to delete it, passing false as a second parameter to tell LINQ to SQL that you don't actually want to update the object using its current values, but that it should track changes from here on.
tbl.Attach(dummy, false)
tbl.DeleteOnSubmit(dummy)
db.SubmitChanges()
Does that make sense?
Edit
When you're only deleting an object, you don't necessarily have to get the record from the database. If you set the ID value of the object and then attach it to the context (as shown above), LINQ to SQL will treat it as if it were retrieved from the database. At that point, calling DeleteOnSubmit should tell the context to construct a DELETE statement in SQL based on that object's primary key value.
However, if you need to retrieve the object for some purpose other than deletion, you'll need to construct an expression to represent the query for that object. So, for example, if you were writing the query manually, you would say something like:
Dim obj = tbl.First(Function(e) e.Id = ID)
So to dynamically build the lambda expression inside the parentheses, you might do something like this:
Dim eParam = Expression.Parameter(rowType, "e")
Dim lambda = Expression.Lambda(Expression.Equal(Expression.MakeMemberAccess(eParam, idMember), Expression.Constant(ID)), eParam)
Then you would need to use reflection to invoke the generic First method:
Dim firstMethod = GetType(Queryable).GetMethods().[Single](Function(m) m.Name = "Single" AndAlso m.GetParameters().Count() = 2).MakeGenericMethod(rowType)
Dim obj = firstMethod.Invoke(Nothing, New Object() {tbl, lambda})