Must I use parameters with an ObjectDataSource update? - asp.net

I have a business object that I've been using, which has a bunch of properties and a Save method, which inserts/updates to the database. The save method is NOT status, so the object needs to be instantiated, and the properties for the DB update/insert get pulled from the object.
Now I'm trying to bind the object to a FormView with the ObjectDataSource. I have it working so it instantiates based on the QueryString parameter, no problem, and populates the textboxes just fine. The UpdateMethod I have set to the Save function. Now it gets stuck.
It seems the ObjectDataSource needs a method with all the fields/properties/textboxes as parameters. I would have thought it would update the object's properties and then call the parameterless Save function. Is this wishful thinking?
Do I now need to change my Save function to include parameters, and change all the instances where it's getting used to this new method, just for this reason?
Thanks
Sean

Unfortunatly it does require params.
I overloaded my insert/update methods to include a few params. Attach the ObjectDataSource to the method with params.
The overloaded Update method calls the original Update method saving all the data. Seems kind of hackish to me, but it works.
Public Sub Update()
Dim isUpdated As Boolean = False
sql = "UPDATE AudioFiles SET Title = #Title, [desc] = #desc, Active = #Active WHERE fileID = #fileID"
conn = New SqlConnection(connString)
conn.Open()
...
End Sub
Public Sub Update(ByVal upFileID As Integer, ByVal upTitle As String, ByVal upDesc As String, ByVal upActive As Boolean)
Dim isUpdated As Boolean = False
Dim audioFile As New AudioFiles(fileID)
If Len(upTitle) > 0 Then
_title = title
End If
...
audioFile.Update()
End Sub

Related

Error when using the WHERE clause in Linq-to-SQL

I have a datacontext that I'm trying to query, the results of which I want to bind to a gridview on a button click. Getting connected to the datacontext works great. I get the 1000s of records I expect. When I try to add the WHERE clause, I run into problems. Here's the button event I'm trying to make it happen at:
Protected Sub btnSearch_Click(ByVal sender As Object, ByVal e As System.EventArgs)
Dim dsource = New MY_DataContext().SV_XXXs '--- This works, the data is all there
gridRec.DataSource = dsource.ToList().Where(Function(dtable) dtable.PN = Session("PN")) '--- this fails
'--- Also tried this, it also did not work ----------------------------------------------------------
'--- gridRec.DataSource = dsource.Where(Function(dtable) dtable.PN = Session("PN")) '--- this fails
'----------------------------------------------------------------------------------------------------
gridRec.DataBind()
End Sub
The session variable is valid and the dsource is populating correctly, but I get the following error when it tries to execute the Where clause:
Evaluation of method
System.Linq.SystemCore_EnumerableDebugView`1[SV_REC].get_Items() calls
into native method System.WeakReference.get_Target(). Evaluation of
native methods in this context is not supported.
Also tried:
Dim results =
(
From T In dsource
Where T.PN = Session("SAFRReceiverPN")
Select T
).ToList
And get this error
Method 'System.Object CompareObjectEqual(System.Object, System.Object,
Boolean)' has no supported translation to SQL.
And tried:
Dim results = From t In dsource Where (t.PN = Session("SAFRReceiverPN")) Select t
nothing seems to work for me when trying a WHERE clause
C# or VB.NET are both cool if you have any suggestions.
Really, any help is appreciated, thanks.
LINQ to SQL doesn't know what to do when you try to access the session inside the query. Instead of doing that, fetch the value from the session before the query and store the result in a local variable, then use that local variable in your query. For example, in C#:
var receiver = (string) Session["SAFRReceiverPN"];
var results = dsource.Where(t => t.PN == receiver);
(I don't bother with query expressions when you're just trying to perform a simple filter.)

Is assigning an object to itself a good idea?

I have two classes, RecordSet and Record. RecordSet has a Generic List(Of Record).
I can add objects to the list by calling my RecordSet.AddRecord(ObjRecord) function, which returns RecordSet. When the list has a count of 200, some processing occurs and a new RecordSet object is returned, otherwise itself is returned and the application can carry on adding Record objects to the list.
My concern is that there will be 200 objects of RecordSet until garbage collection does it's sweep. Is this a good idea?
Public Class RecordSet
Private lstRecords As New List(Of Record)
Public Function AddRecord(SomeVariable) AS RecordSet
lstRecords.Add(New Record())
If lstRecords.Count = 200 Then
Me.ProcessTheRecords()
Return New RecordSet()
Else
Return Me
End If
End Function
Private Sub ProcessTheRecords()
'Do stuff in here
End Sub
Private Class Record
Public Sub New()
End Sub
End Class
End Class
Then in my application I call:
Dim objRecordSet AS New RecordSet
For Each VariableName In SomeList
objRecordSet = objRecordSet.AddRecord(VariableName)
Next
'Process the remaining objects in objRecordSet here.
First of all, this is really bad pratice, it's hard to follow the code for someone new and is a potential bug source. Instead of returning urself every time, change your design.
Change your function to this:
Public Sub AddRecord(SomeVariable)
lstRecords.Add(New Record()) <--- should't you be doing something with SomeVariable?!
If lstRecords.Count = 200 Then
Me.ProcessTheRecords()
end if
End Function
Private Sub ProcessTheRecords()
'Do stuff in here
Me.lstRecords.clear()
End Sub
Now AddRecord does exactly what it says it does - it adds a new record and modifies the recordSet. ProcessTheRecords does the processing, as its supposed to do, and if u need to clear the list container - oh well, just clear it.
I strongly recommed to read this wiki article about
Cohesion.
Just as a proposiontion, the AddRecord could be a function of return type Boolean, which indicates the success of the operation (maybe an error or exception can be raised by the processing function?).
It's much cleaner now, isn't it?

.Net: code for BtnLock_Click

I have been trying to apply a solution to some functionality that a user requires on their system.
A user requires me to implement a locking system on their system. They have multiple users which may require to access the site, but the user would like the ability for them to independently lock a records in the web site site, for them to add notes to and to then unlock this so other users are able to do the same.
I have a button on my web page simply named btnLock and i have added an additional column in my database called LockedBy and have the following stored procedure...
ALTER PROCEDURE LockWeeklyTest
(
#AgendaID BIGINT,
#LockingUser VARCHAR(20)
)
AS
BEGIN
SET NOCOUNT ON
UPDATE
WeeklyAgenda
SET
LockedBy = #LockingUser
WHERE
AgendaID = #AgendaID
AND
LockedBy IS NULL
END
I have a class named Weekly Class and have the following code...
Public Shared Sub LockWeeklyAgenda(ByVal WeeklyClass As WeeklyClass)
Using dbConnection As New SqlConnection(ConfigurationManager.AppSettings("dbConnection"))
dbConnection.Open()
Dim dbTrans As SqlTransaction
dbTrans = dbConnection.BeginTransaction()
Using dbCommand As SqlCommand = dbConnection.CreateCommand
With dbCommand
.Transaction = dbTrans
.CommandType = CommandType.StoredProcedure
.CommandText = "LockWeeklyTest"
'Add Parameters for Update
.Parameters.AddWithValue("#AgendaID", WeeklyClass.AgendaID)
.Parameters.AddWithValue("#LockingUser", WeeklyClass.LockedBy)
dbCommand.ExecuteNonQuery()
End With
End Using 'dbCommand
dbTrans.Commit()
End Using
End Sub
I was thinking that the below code for the butlock would populate my Loggedby field with the username but this isnt the case.
Protected Sub btnLock_Click(sender As Object, e As System.EventArgs) Handles btnLock.Click
Dim lock As New WeeklyClass
If lock.LockedBy = "Null" Then
lock.LockedBy = System.Environment.UserName
'lock.AgendaID = AgendaID
End If
' save to the database using the Class DAL
WeeklyClassDAL.LockWeeklyAgenda(lock)
End Sub
I know that the Stored Procedure works as i have tested with the following statement as an example...
EXEC LockWeeklyTest 11, 'Betty'
Im sure that its something to do with the btnlock_click, but im not 100% sure what this is.
Any help is much appriechiated.
Your problem is this line:
If lock.LockedBy = "Null" Then
"Null" is actually a string containing the word Null. What you're after is:
If String.IsNullOrEmpty(lock.LockedBy) Then
That way, if it is actually null or empty, your LockedBy will be set. Currently, it's only setting the LockedBy if LockedBy already equals the string value "Null", which it won't directly after being declared. Is this logic really necessary considering LockedBy will always be null directly after you've declared the WeeklyClass?
Something doesn't look quite right with the AgendaID:
During the button click event the value has been commented out but is still passed through to the stored procedure inside the data layer's 'LockWeeklyAgenda' method.
It's also not defined as a nullable parameter inside the stored procedure itself, so the value that's being sent would depend on the WeeklyClass class' constructor..
can you please also show how the WeeklyClass code looks like?

How to check if sqlParameter is empty?

I have a class, which has many "New()" functions to initiate it with various parameters. I would like to create a New() function that will init the class with no arguments. The problem is there is a "fillData" function which fills the data for the class, and takes in the stored procedure to do the work, but has a stored procedure parameter. I don't want to create a new fillData function, but would like to use the fillData function with no additional need for a stored procedure. My way of going about this was to pass an empty SqlParameter var to the fillData function, but no mater what I do, when I check the params parameter for being empty, it always seems to think there's stuff in there.
I would like to check if this "params" parameter is empty:
Public Sub New()
'just created this so i could pass something
'and continue using fillData as is.
Dim p(1) As SqlParameter
Dim db As sqldb.command
db = New sqldb.command(ConfigurationManager.ConnectionStrings("sqlConnectionString").ConnectionString)
fillData("r2m_getAllListingsSorted", p)
End Sub
...
Private Sub fillData(ByVal sp As String, ByVal params As SqlParameter())
Dim db As sqldb.command
Dim r As SqlDataReader
db = New sqldb.command(ConfigurationManager.ConnectionStrings("sqlConnectionString").ConnectionString)
'right here, im having the trouble, seems no matter how I try to "params",
'the code always defaults to db.executeReader(sp, p)
'I've tried params.Length = 0 and params.ToString = "" also.
If params.Value Then
r = db.executeReader(sp)
Else
r = db.executeReader(sp, params)
End If
How would I modify this so i could continue to use the fillData function, without passing a SqlParameter parameter to it?
Thank you!
You can make your SqlParameter Optional and give it a default value of Nothing:
Private Sub fillData(ByVal sp As String,
ByVal Optional params As SqlParameter() = Nothing)
Then call the method without the params argument:
fillData("StoredProcName")
You can then check the parameter inside the fillData method to see if it's Nothing before using it.
If params is Nothing Then
// Do something if there's no params
Else
// Do something if there is params
End If

Save changes to Entity model to the database

I'm new to Entity Framework and am expanding an existing codebase. I'm using jQuery to pass the needed info back to the server ajaxy style, so I can't use TryUpdateModel(). Here's the code:
<HttpPost()>
Function UpdateRoster() As JsonResult
Dim model As New Models.ViewModels.PlayerAdmin
Dim jsonString As String = Request.Form("json")
model = Deserialise(Of Models.ViewModels.PlayerAdmin)(jsonString)
For Each playerAdminPlayer As Models.ViewModels.PlayerAdminPlayer In model.Roster
Dim playerToTeam As New DAL.PlayersToTeam
Dim player As DAL.Player = PlayerAdminManager.GetPlayerById(playerAdminPlayer.PlayerId)
player.FirstName = playerAdminPlayer.FirstName
PlayerAdminManager.SaveChanges()
Next playerAdminPlayer
Dim playerAfter As DAL.Player = PlayerAdminManager.GetPlayerById(model.Roster.First.PlayerId)
Return Json(New With {.success = False, .message = playerAfter.FirstName})
End Function
Deserialise is a helper function that converts the incoming JSON string to a vb object.
Things seem to work fine in that player successfully loads from the DB and playerAdminPlayer is the correct object from the JSON string. However, when I call PlayerAdminManager.SaveChanges() (which just passes the call the db.SaveChanges() the result is always 0, even if there is a change (not sure if that is expected).
playerAfter was my attempt to see if changes were actually being saved. It seems to work correctly, in that playerAfter.FirstName is the newly updated first name.
PlayerAdminManager.GetPlayerById(integer) pulls from the DB, so I would think that, since changes are observed in playerAfter, that those changes were saved to the DB. However, when I reload the web page (which pulls from the DB), the old values are there.
Any ideas?
Here are some of the functions I mention:
Function GetPlayerById(ByVal Id As Integer) As DAL.Player
Return Container.Players.Where(Function(o) o.PlayerId = Id And o.IsVisible = True).SingleOrDefault
End Function
Sub SaveChanges()
Dim numberOfChanges As Integer = Container.SaveChanges()
Debug.WriteLine("No conflicts. " & numberOfChanges.ToString() & " updates saved.")
End Sub
EDIT
Container code:
Private _Container As DAL.LateralSportsContainer
Protected ReadOnly Property Container As DAL.LateralSportsContainer
Get
If _Container Is Nothing Then
Dim connStr As New System.Data.EntityClient.EntityConnectionStringBuilder
connStr.ProviderConnectionString = Web.Configuration.WebConfigurationManager.ConnectionStrings("ApplicationServices").ConnectionString
connStr.Metadata = "res://*/Lateral.csdl|res://*/Lateral.ssdl|res://*/Lateral.msl"
connStr.Provider = "System.Data.SqlClient"
_Container = New DAL.LateralSportsContainer(connStr.ConnectionString)
End If
Return _Container
End Get
End Property
Turns out I was using a non static (shared) Container. I had 2 Manager classes that both inherited from a BaseManager class were the Container was defined. I was executing the query command in one Manager and saving in another.
Doh!

Resources