8

Using VB.net, create a new class called staff, with three properties: Name , LastName, ID - should be suitable for use as a primary key in a database.

Provide a class constructor to populate Name and LastName. ID should be auto-generated within the constructor and should not be passed in.

I know how to create a class, properties and constructor, I just need to know how to auto-generate ID field within the constructor. Is it possible to do this?

what I usually do is either make the id field in database as identity field and primary key so it automatically inserts the next available id or In my application I read the last ID from database and add one to it. But I need to know how to auto-generate ID field within the constructor.

5
  • Does the ID being generated in the constructor need to be unique only among all the objects in memory, or does it need to be unique among all the objects that are already stored to the DB? Commented Jan 29, 2014 at 14:23
  • It needs to be unique in DB as question says it should be suitable for use as a primary key in a database.
    – Diana
    Commented Jan 29, 2014 at 14:28
  • 1
    In that case, there is no way for the constructor to generate a unique ID except as a GUID, or something similar. There is no way to know what an auto-incrementing ID is until after it is inserted into the DB. Commented Jan 29, 2014 at 14:31
  • Exactly, you are right. Its common sense, you need to read the database to know what was the last ID inserted.
    – Diana
    Commented Jan 29, 2014 at 14:36
  • 1
    @Diana yes and even in such case (reading back from DB) you have to consider concurrency. It's all but not an easy task to be done properly (unless you use something that is - should be - unique by itself like a GUID). Commented Jan 29, 2014 at 14:39

4 Answers 4

11

Guid

If you do not have any constrain about ID type you can use a GUID:

Dim id As Guid = Guid.NewGuid()

You may even keep it as string:

Dim id As String = Guid.NewGuid().ToString("N")

That should be granted to be unique across different machines (to satisfy your requirement that it has to be suitable for use as a primary key in a database). See also this post.

Timestamp

That was worse case, if you do not have such strict requirement (uniqueness across a network) you may use a timestamp. Of course, in this case, you have to consider more issues:

  • Legal time: time goes back and forward twice per year.
  • Zones: what if user enter data in London and then he moves to New York?
  • Concurrency: you have to assume no one else adds records to your database (you may have collisions if they use a different technique). Also you can't apply this if execution is concurrent (multiple instance of your program running together).
  • Timer granularity: system date has a coarse granularity: if you construct many objects in a short period of time then you may have duplicate IDs. Workaround in this post.

Counter

If all these conditions are satisfied:

  • Multiple instances of your application won't run in parallel.
  • You're working on a single computer (not a network).
  • Database is empty every time your application starts.

You may use a Shared counter incremented each time a new object is constructed. If system timer granularity isn't an issue (see paragraph about timestamp)you may use system up time as ID. With limitations about granularity it should work even with multiple instances of the same application running concurrently.

If you use a Shared field you have to deal with synchronization issues. As suggested in this comment you may use a SyncLock. As alternative you may use an Interlocked.Increment operation.

Hash code

If all condistions for a counter are satisfied and this one also:

  • Your application is 32 bit.
  • Your object is not a ValueType and it doesn't override GetHashCode() method.

You can use hash-code (obtained with GetHashCode()) because (from MSDN):

In other words, two objects for which the ReferenceEquals method returns true have identical hash codes.

Because Object.ReferenceEquals() returns true only if you compare same instance then each instance will have a unique hash code (because in a 32 bit application hash code is object reference itself). Be aware this is an implementation detail and it may change.

Random number

I know this may shock someone but a good random number generator for a 64 bit value has a very low probability of collisions. I repeat very very low probability (see this article for more math details). Just do not use System.Random for this!

According to which seed you use you may be able to generate random numbers in a network scenario too (do not forget - citation needed - that earlier drafts for one local network protocol proposed a 32 bit random number as address, it has been changed because of bad feedback from users but it doesn't mean it can't work).

2
  • GetHashCode is not guaranteed to be unique. It's only intended to be evenly distributed. From the MSDN: "do not use the default implementation of this method as a unique object identifier" Commented Jan 29, 2014 at 14:27
  • +1, but one more thing... It's worth mentioning that if you do a Shared counter, you'd need to wrap it in a SyncLock block to make it thread-safe--if that's a concern. Commented Jan 29, 2014 at 14:33
1

You want a number that won't repeat ever! So why not just use this?

    Dim dateAndTime As Date
    dateAndTime = Now
    TextBoxPID.Text = Format(dateAndTime, "yyyyMMddHHmmss").ToString

Unless your data entries are going to take place in milliseconds, this solution works great. If you are running into a millisecond issue then just add a counter to the end of the string.

    counter +=1
    TextBoxPID.Text = Format(dateAndTime, "yyyyMMddHHmmss").ToString & counter.ToString

If you are working on a network and have several people doing data entry then add their employee id to the string. There are easy solution to every issue, but in most, if not all cases, this will work without issue.

2
  • And if you are worried about time changes, unless you are doing data entry at 2am when it changes backwards in the fall, there will be no issues. Most companies don't like to keep employees up that late. Commented Jul 8, 2015 at 11:12
  • Thank you. That solution suits me.
    – evry1falls
    Commented Jan 27, 2021 at 19:34
1

Generate Random Unique User ID depending on SNTP server.

My requirements are a bit different; yet I needed to generate a random and unique User ID, that is 10 numbers, spending fair time couldn't find a suitable solution. so I ended up with the following function; its unique and random result.

As per one application instant on one test machine it is incremental unique result; because the user will generate the ten digits one time on a non pre-selective timestamp. In addition to playing with the random alpha prefix; I hope this function can provide a solution:

Imports System.Globalization
Imports System.Net

Public Class GetNetTime
    Public Shared Function GetUTC()
        ' connect to google servers
        ' you could use some SNTP time servers but can't be sure port will be open
        ' or you could just ping your own webserver
        Dim myNetRequest As WebRequest = HttpWebRequest.Create("http://www.example.com")
        ' read response header from connection
        Dim response = myNetRequest.GetResponse()
        ' read date/time header
        ' assume its UTC format
        Dim GlobalUTC As String = response.Headers("date").ToString
        ' convert string to datetime object
        Dim parsedDateTime As DateTime = DateTime.Parse(GlobalUTC)
        ' get UNIX time stamp
        Dim unixTime = (parsedDateTime - New DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds
        Return unixTime 
    End Function
End Class

To test the output, you could add:

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim utc As String = GetNetTime.GetUTC
        ' add random alpha prefix to UNIX time stamp
        Dim sPrefix As String = ""
        Dim rdm As New Random()
        For i As Integer = 1 To 3 ' if you need more than 3 alpah random charachters adjust i length
            sPrefix &= ChrW(rdm.Next(65, 90))
        Next
        MsgBox(sPrefix & utc) ' OR MsgBox("ID" & sPrefix & utc)
        ' code here to use result
    End Sub

I find this solution more useful than querying the SQL table and read last record id and do increment.

Notes:

  • Please don't mind long answer; as I tried to comment the code and explain the scenario in details.
  • I think this is good for generating UserID for application running on multiple workstations.
  • Please don't put the function in for ... loop or exhaust run it.

Output examples:

GYK1501270543

VWT1501270606

WRH1501270634

SKI1501270648

QXL1501270716
0

This is also based on @wpcoder answers above but a basic form and this one works for me

    Public Function UIDGen(ByRef f As String) As String
        Dim currentTime As DateTime = DateTime.UtcNow
        Dim StringTime As String = currentTime.ToString
        Dim parsedDateTime As DateTime = DateTime.Parse(StringTime)
        Dim unixTime = (parsedDateTime - New DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds
        Dim utcString As String = unixTime.ToString
        Dim sPrefix As String = ""
        Dim rdm As New Random()

        For i As Integer = 1 To 3 ' 3 Letters enough ?
            sPrefix &= ChrW(rdm.Next(65, 90))
        Next
        f = (sPrefix & utcString)
        Return f
    End Function

Not the answer you're looking for? Browse other questions tagged or ask your own question.