Access 2016, VBA; I am trying to declare a public variable (User's window login), and it keeps "Forgetting" the variable between the function and the form_load
Module:
Option Compare Database
Public vUser As String
Start Form:
Public Function fnUserID() As String
Set Wshnetwork = CreateObject("wscript.Network")
fnUserID = Wshnetwork.UserName
End Function
Public Function SetUserID()
vUser = fnUserID
End Function
Private Sub Form_Load()
Call SetUserID
txtBox.Value = vUser
End Sub
Now I have this exact code (same var names, etc) working in a second Access db. What am I missing that is making this one not work correctly?
It does work as is in a test here, and it works in your other form.
So, recreate the offending form. Somehow the current code module may be corrupted.
Scope is a tricky thing, especially if you're not using Option Explicit. You should always use explicit declarations, and use Option Explicit at the top of all modules in VBA.
You can explicitly refer to the global scope vUser in that module, by adjusting your code to use ModuleName.vUser:
Public Function fnUserID() As String
Set Wshnetwork = CreateObject("wscript.Network")
fnUserID = Wshnetwork.UserName
End Function
Public Function SetUserID()
Module1.vUser = fnUserID
End Function
Private Sub Form_Load()
Call SetUserID
txtBox.Value = Module1.vUser
End Sub
Popular alternatives are:
Use a TempVar: TempVars.vUser. Advantages include being able to refer to the TempVar in queries, form expressions, and macro's.
Use a predeclared class. Advantages include separating authentication code from forms, and making it easier to extend authentication.
Related
What is the VBA code to parse a value into a different field in the db when a checkbox is clicked?
Example code (that doesn't work):
Private Sub Step_1_Click()
If Step_1.Value = True Then
Step1_score.Value = 10
End if
End Sub
I removed the "value" and got no code errors but the 10 is not showing up in the Step1_score variable in the db. Any advise on the VBA code to parse a value from a checkmark? Thanks!
You probably want to use the _AfterUpdate event to make sure the value of Step_1 gets changed before the event fires:
Private Sub Step_1_AfterUpdate()
If Step_1.Value = True Then
Step1_score.Value = 10
End if
End Sub
I have a function that I want to return different Listboxes based on a string argument.
Here is the function:
Here is the function:
Private Function returnList(name As String) As AccessObject
If name = "app" Then
returnList = Me.Controls("List61")
'I have also tried the following:
'returnList = Me.List61, returnList = Forms![Daily Reports]![List61]
ElseIf name = "lpar" Then
'..several more cases
End If
End Function
Whenever I try to call it, I get a "Run-time error '91': Object variable or With block variable not set." And when I use the debugger, it tells me that the reference to list61(Me.list61, Me.Controls("List61")) is null.
Anyone have any idea how to fix this? Any help would me much appreciated.
The most important thing to note is; as you are now handling "Objects" instead of "variables" you have to put the word "Set" in front of the object variable. Also change the AccessObject type to ListBox.
Private Function returnList(name As String) As ListBox
If name = "app" Then
Set returnList = Me.Controls("List61")
'I have also tried the following:
'returnList = Me.List61, returnList = Forms![Daily Reports]![List61]
ElseIf name = "lpar" Then
'..several more cases
End If
End Function
I have this piece of code in excel:
Private Function RelCell(NmdRng as String) as Range
Set RelCell = Range(NmdRng).Cells(1,1)
End Function
it gives the runtime error "91': object variable or with block variable not set.
I really don't know what is the problem with my function.. someone does?
I don't know if this is the problem but your are only setting the range and aren't returning anything from the function.
Try declaring a range variable with a different name as the function and return that.
Actually, you should be able to return a range from a UDF as described in this MSDN Thread.
Here is the code given by the MVP:
Function GetMeRange(rStartCell As Range, lRows As Long, iColumns As Integer) As Range
Set GetMe = rStartCell.Resize(lRows, iColumns) ' note the use of Set here since we are setting an object variable
End Function
(and it works)
Tiago's comment points out a very right thing, as you want to access a named range, it should be defined first.
You can try to set a breakpoint in your UDF and see if the Range(NmdRng) is defined.
Your named range already has a cell reference attached to it, so you shouldn't need to have the .Cells(1,1) at the end of it.
Using the .Range(nmdRng) property alone will return the range object you are looking for.
Try:
Private Function RelCell(NmdRng as String) as Range
Set RelCell = Range("NmdRng")
End Function
Please rewrite your code and test it as follows :
Private Function RelCell(NmdRng as String) as Range
Dim TestRange As Range
Set TestRange=Range(NmdRng)
TestRange.Activate 'I think that error will occur here because, NmdRng is somehow invalid
Set RelCell = TestRange.Cells(1,1)
End Function
When using a Linq-to-SQL class, how can I make a simple copy of an entity and save it?
My entity has a guid for a unique ID that gets automatically generated in the SQL Server.
I don't require a "deep clone".
I tried to use some clone methods that are out there but I couldn't figure out how to get everything serialized that needed to be serialized (got stuck on the DataContext not being serializable).
Can I just get an entity, detach it from the DataContext, null out the unique ID and InsertOnSubmit in a new DataContext? If so, how would I do this?
VB.net code preferred but not required.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
UPDATE:
Public Shared Function ReIssue(RequestID As Guid) As Guid
Dim req As Request
Dim new_req As Request
Using dc1 As New MBDataContext()
req = (From r In dc1.Requests Where r.ID = RequestID).Single()
End Using
new_req = req
new_req.ID = Guid.Empty
new_req.CreateDate = Nothing
Using dc2 As New MBDataContext()
dc2.Requests.InsertOnSubmit(new_req)
dc2.SubmitChanges()
End Using
End Function
I get an error: An attempt has been made to Attach or Add an entity that is not new, perhaps having been loaded from another DataContext. This is not supported.
on this line: dc2.Requests.InsertOnSubmit(new_req)
Nulling out the unique id and then calling InsertOnSubmit is the right way to go. Some things you have to consider though:
What is the type of the id? Is it an int? A Guid? Is it nullable? If it is nullable, make sure to set it to null, if it is an int, then to 0, or a Guid, then to Guid.Empty.
Does the type have a timestamp of some kind? If so, then you have to reset/set it to null as well, depending on the type.
Once you've done that, you can call InsertOnSubmit and then SubmitChanges and the change should take place.
Note, if you are doing this for a large number of records, you are better off writing a stored procedure which will perform the insert into the table using a select from the other table. It will be much faster that way (you won't be loading the data from the database into memory then pushing it back, inserting the records one at a time).
This method seems to have worked perfectly.
Making the final code look like this:
Public Shared Function ReIssue(RequestID As Guid) As Guid
Using dc As New MBDataContext()
Dim req As Request
req = (From r In dc.Requests Where r.ID = RequestID).Single()
Dim new_req As Request = DirectCast(Entity.Copy(req, New Request()), Request)
dc.Requests.InsertOnSubmit(new_req)
dc.SubmitChanges()
req.ActiveRequestParentID = new_req.ID
dc.SubmitChanges()
Return new_req.ID
End Using
End Function
Public NotInheritable Class Entity
Private Sub New()
End Sub
Public Shared Function Copy(source As Object, destination As Object) As Object
Dim sourceProps As System.Reflection.PropertyInfo() = source.[GetType]().GetProperties()
Dim destinationProps As System.Reflection.PropertyInfo() = destination.[GetType]().GetProperties()
For Each sourceProp As System.Reflection.PropertyInfo In sourceProps
Dim column As ColumnAttribute = TryCast(Attribute.GetCustomAttribute(sourceProp, GetType(ColumnAttribute)), ColumnAttribute)
If column IsNot Nothing AndAlso Not column.IsPrimaryKey Then
For Each destinationProp As System.Reflection.PropertyInfo In destinationProps
If sourceProp.Name = destinationProp.Name AndAlso destinationProp.CanWrite Then
destinationProp.SetValue(destination, sourceProp.GetValue(source, Nothing), Nothing)
Exit For
End If
Next
End If
Next
Return destination
End Function
End Class
I want to initialize a class with data coming from a MySql db. Some fields can be null:
Dim dr As MySqlDataReader = ...
Dim item As New Item(dr.GetInt16(0), dr.GetString(1), dr.GetString(2))
Suppose the last two fields could be NULL In the db, so that calling GetString on that field causes an exception.
I could certainly write code to test for NULLs before I get each field:
dim field1 as String
if ( dr.IsDbNull(1) )
field1 = Nothing ' or even ""
else
field1 = dr.GetString(1)
But if you have many fields this is an "ifs" nightmare.
To this purpose I rewrote the IIf VB function to make it more typed, thus to avoid casts:
Namespace Util
Public Shared Function IIf(Of T)(ByVal condition As Boolean, ByVal iftrue As T, ByVal iffalse As T) As T
If condition Then Return iftrue Else Return iffalse
End Function
So that I could write something like:
Dim item As New Item(
dr.GetInt16(0),
Util.IIf(dr.IsDbNull(1), "", dr.GetString(1),
Util.IIf(dr.IsDbNull(2), "", dr.GetString(2))
The typed IIf works well in other cases, but unfortunately it doesn't in this instance, because being it a normal function and not a language keyword, each inpout parameter is evaluated during the call, and when the field is NULL the exception is raised.
Can you think of an elegant if-less solution?
First off, I'd recommend you to use an ORM mapper - there are very few cases nowadays when you have to do manual "mapping".
If this is one of these cases, I'd recommend you to use field names instead of indexes while accessing Data Reader.
And to answer your original question: try extension methods. Sorry for C#, but VB.NET syntax drives me nuts:
public static class DbDataReaderExtensions
{
public static T GetField<T>(this DbDataReader dbDataReader, string fieldName,
T defaultValue)
{
if(dbDataReader.IsDBNull(fieldName))
return defaultValue;
return (T)dbDataReader[fieldName];
}
}
Thanks.
I have looked at many ORMs and I don't like them for one reason or another, so I decided to call plain stored procedures to get data. Can you advice something powerful yet simple?
You're right about to use field names, it is safer, even if a little bit slower.
I had just arrived to the same conclusion with the method, but what I still don't like is the type conversion:
Public Shared Function IfNull(Of T)(ByVal dr As MySqlDataReader, ByVal index As Integer, ByVal _default As T) As T
If dr.IsDBNull(index) Then
Return _default
Else
Return CType(dr.GetValue(index), T)
End If
End Function
I would like to do something more elegant to get the "real" data type from the reader.