I got a stored procedure that reads a table and insert those data to antoher table. That's the way how it works because the first table imports data from excel using a package with SSIS.
In EF4 I imported the SP and create function import:
This SP has 2 IN variables and 2 OUT varibales.
The IN varibales are parameters and OUT variables are a message and the number of records created.
I put the code generated:
#Region "Function Imports"
''' <summary>
''' No Metadata Documentation available.
''' </summary>
''' <param name="parIDPoliza">No Metadata Documentation available.</param>
''' <param name="parFechaActual">No Metadata Documentation available.</param>
''' <param name="varError">No Metadata Documentation available.</param>
''' <param name="varKontador">No Metadata Documentation available.</param>
Public Function spCargaArchivos(parIDPoliza As Nullable(Of Global.System.Int64), parFechaActual As Nullable(Of Global.System.DateTime), varError As ObjectParameter, varKontador As ObjectParameter) As Integer
Dim parIDPolizaParameter As ObjectParameter
If (parIDPoliza.HasValue) Then
parIDPolizaParameter = New ObjectParameter("parIDPoliza", parIDPoliza)
Else
parIDPolizaParameter = New ObjectParameter("parIDPoliza", GetType(Global.System.Int64))
End If
Dim parFechaActualParameter As ObjectParameter
If (parFechaActual.HasValue) Then
parFechaActualParameter = New ObjectParameter("parFechaActual", parFechaActual)
Else
parFechaActualParameter = New ObjectParameter("parFechaActual", GetType(Global.System.DateTime))
End If
Return MyBase.ExecuteFunction("spCargaArchivos", parIDPolizaParameter, parFechaActualParameter, varError, varKontador)
End Function
#End Region
But when I try to execute the SP I get error:
The parameter at index 2 in the parameters array is null
Execution
Dim varMensaje As Objects.ObjectParameter = Nothing
Dim varError As Objects.ObjectParameter = Nothing
Dim varRespuesta As Integer = varEntidades.spCargaArchivos(parIDPoliza, Now.Date, varError, varMensaje)
Any suggestion??
Finally I could solve this.... after two hard days.
I don't know if it's a bug or not but the error is how to send OUTPUT variables.
The types are the same that Function Import in Model Browser properties
Dim varTotalRegistros As Objects.ObjectParameter = New Objects.ObjectParameter("varKontador", GetType(Global.System.Int64))
Dim varError As Objects.ObjectParameter = New Objects.ObjectParameter("varError", GetType(Global.System.String))
Dim varRespuesta As Integer = varEntidades.spCargaArchivos(parIDPoliza, Now.Date, varError, varTotalRegistros)
Good luck!!
Related
I want to write below SQL query using LINQ Query in VB.Net,
Could someone please suggest if there is any way to write it?
Select Count(Distinct(User_ID)) from tbl_CTRL where Req_ID = "R1" AND User_ID in ('001','002','004','005')
TABLE: tbl_CTRL
User_ID Req_ID
001 R1
002 R2
003 R1
004 R1
005 R2
001 R2
002 R3
Expected Output is:
Count= 2
Is this what you want?
'Assuming you have a DataTable
'Dim tbl_CTRL As DataTable = New DataTable
Dim elCounts As Integer = (From element In tbl_CTRL
Where {"001", "002", "004", "005"}.Contains(CStr(element.Field(Of Object)("User_ID")))
Select element
Distinct).Count
The following has not been fully test but should work for what you want. In the example below the WHERE IN condition when dynamically created uses parameters rather than injection in this case a comma delimited list of values for the command.
Full working code sample can be found in the following GitHub repository.
Finally SQL
SELECT C.CustomerIdentifier ,
C.CompanyName ,
C.ContactName ,
C.ContactTypeIdentifier ,
FORMAT(C.ModifiedDate, 'MM-dd-yyyy', 'en-US') AS ModifiedDate,
CT.ContactTitle
FROM dbo.Customers AS C
INNER JOIN dbo.ContactType AS CT ON C.ContactTypeIdentifier = CT.ContactTypeIdentifier
WHERE CT.ContactTitle IN (#CTContactTitle0,#CTContactTitle1) AND Req_ID = "R1"
ORDER BY C.CompanyName
Code to create WHERE IN
Imports System.Data.SqlClient
Imports System.Runtime.CompilerServices
Imports System.Text.RegularExpressions
''' <summary>
''' Contains methods to create dynamic WHERE IN conditions on a single field
''' </summary>
''' <remarks>
''' These methods are not meant to handle every single condition, they are
''' for simple IN clauses e.g.
'''
''' WHERE SomeField IN (1,2,3)
''' WHERE SomeField IN ('June','April')
''' WHERE YEAR(SomeField) IN (2008,2007,2018)
''' WHERE SomeField IN ('4-4-1960','9-22-1989')
'''
''' If a function is year that has arguments these methods will not handle
''' them "as is".
'''
''' </remarks>
Public Module SqlWhereInParameterBuilder
''' <summary>
''' Create a SQL SELECT statement which is then passed off to
''' AddParamsToCommand to create a parameter for each value.
''' </summary>
''' <typeparam name="T">SELECT Statement with WHERE condition</typeparam>
''' <param name="partialClause">Base SQL SELECT statement</param>
''' <param name="paramPrefix">WHERE IN field</param>
''' <param name="parameters">Value list for WHERE IN</param>
''' <returns>SELECT Statement with WHERE condition ready to populate values</returns>
Public Function BuildWhereInClause(Of T)(partialClause As String, paramPrefix As String, parameters As IEnumerable(Of T)) As String
paramPrefix = StripFunction(paramPrefix)
Dim parameterNames = parameters.Select(
Function(paramText, paramNumber) $"#{paramPrefix.Replace(".", "")}{paramNumber}").ToArray()
Dim whereInClause = String.Format(partialClause.Trim(), String.Join(",", parameterNames))
Return whereInClause
End Function
''' <summary>
''' Create a parameter for each value in parameters
''' </summary>
''' <typeparam name="T">Command with parameters setup</typeparam>
''' <param name="cmd">Command object</param>
''' <param name="paramPrefix">Field name for the WHERE IN</param>
''' <param name="parameters">Values for the WHERE IN</param>
<Extension>
Public Sub AddParamsToCommand(Of T)(cmd As SqlCommand, paramPrefix As String, parameters As IEnumerable(Of T))
paramPrefix = StripFunction(paramPrefix)
Dim parameterValues = parameters.Select(Function(paramText) paramText).ToArray()
Dim parameterNames() As String = parameterValues.Select(
Function(paramText, paramNumber) $"#{paramPrefix.Replace(".", "")}{paramNumber}").ToArray()
For index As Integer = 0 To parameterNames.Length - 1
cmd.Parameters.AddWithValue(parameterNames(index), parameterValues(index))
Next
'
' Display what a hacker would see
'
If Debugger.IsAttached Then
Console.WriteLine(cmd.CommandText)
End If
End Sub
''' <summary>
''' Used to get a field name from a function e.g. YEAR(ActiveDate)
''' which will return ActiveDate.
''' </summary>
''' <param name="pValue"></param>
''' <returns></returns>
Private Function StripFunction(pValue As String) As String
If pValue.Contains("(") Then
Dim regularExpressionPattern As String = "(?<=\()[^}]*(?=\))"
Dim re As New Regex(regularExpressionPattern)
Return re.Matches(pValue)(0).ToString()
Else
Return pValue
End If
End Function
End Module
Here is a roughed out example in a console project (Imports SqlHelpers) is a class project from above.
Imports System
Imports System.Data
Imports SqlHelpers
Module Program
Sub Main(args As String())
Dim contacts = New List(Of String) From {"May Jones", "Tim O'Brian"}
Examples.ReadCustomersByContactType(contacts)
End Sub
End Module
Public Class Examples
Public Shared Function ReadCustomersByContactType(pContactTitleList As List(Of String)) As DataTable
'mHasException = False
' field which the WHERE IN will use
Dim parameterPrefix = "CT.ContactTitle"
' Base SELECT Statement
Dim selectStatement =
<SQL>
SELECT C.CustomerIdentifier ,
C.CompanyName ,
C.ContactName ,
C.ContactTypeIdentifier ,
FORMAT(C.ModifiedDate, 'MM-dd-yyyy', 'en-US') AS ModifiedDate,
CT.ContactTitle
FROM dbo.Customers AS C
INNER JOIN dbo.ContactType AS CT ON C.ContactTypeIdentifier = CT.ContactTypeIdentifier
WHERE <%= parameterPrefix %> IN ({0}) AND Req_ID = "R1"
ORDER BY C.CompanyName
</SQL>.Value
' Builds the SELECT statement minus values
Dim CommandText = BuildWhereInClause(selectStatement, parameterPrefix, pContactTitleList)
Dim dt As New DataTable
Using cn As New SqlClient.SqlConnection
Using cmd As New SqlClient.SqlCommand
cmd.CommandText = CommandText
'
' Add values for command parameters
'
cmd.AddParamsToCommand(parameterPrefix, pContactTitleList)
Console.WriteLine()
Try
'cn.Open()
'dt.Load(cmd.ExecuteReader)
Catch ex As Exception
'mHasException = True
'mLastException = ex
End Try
End Using
End Using
Return dt
End Function
End Class
In the Git repository there is also a custom TextBox if needed.
I have a stored procedure with a CLOB as an input.
I'm looking to do a refactor, so my Oracle library is not directly referenced. When I create a parameter from the object, I'm getting back an IDbDataParameter object.
Passing a string to it without defining the type seems to work fine (setting the name and value).
However, the text gets cut off at 32767, the maximum length for Oracle VARCHAR.
So, my question is, how do I set the OracleDbType to type Clob, without having to expose the assembly or use reflection. I tried using a DbType of binary and it failed. I'd rather not load the library of use reflection if there is a better way.
Here's some sample code:
''' <summary>
''' Creates a Parameter
''' </summary>
''' <param name="name"></param>
''' <param name="value"></param>
''' <returns></returns>
Public Function CreateParameter(ByVal name As String, ByVal value As String) As IDbDataParameter
Dim parameter As IDbDataParameter = m_Db.CreateParameter()
parameter.ParameterName = name
parameter.Value = value
Return parameter
End Function
And from the caller. the p_notes parameter is what I want to be a CLOB.
oDAL = New DAL.DataAccessLayer(m_BSL)
Dim parameters As New List(Of IDbDataParameter)
parameters.Add(oDAL.CreateParameter("p_no", compNo))
parameters.Add(oDAL.CreateParameter("p_sys", m_BSL.CurrentSystem.Description.ToString))
parameters.Add(oDAL.CreateParameter("p_notes", notes))
parameters.Add(oDAL.CreateParameter("p_chuser", m_BSL.CurrentUser.ToString))
oDAL.Exec_SP("P_UPDATE_MASTSTAT_NOTES", parameters.ToArray())
So is there a way to set DbType in such a way that it will assign OracleDbType to CLOB?
I am trying my best not to use late binding with the getObject function. How ever i know i wont be looked down upon turning strict off in only One class.
My question is i can't find what to declare my member type of.
Dim restPoint = GetObject("winmgmts:\\.\root\default:Systemrestore")
If restPoint IsNot Nothing Then
If restPoint.CreateRestorePoint("test restore point system", 12, 100) = 0 Then
MsgBox("Restore Point created successfully")
Else
MsgBox("Could not create restore point!")
End If
End If
I have spent hours trying to research msdn createrestorepoint come from. I don't want to use WMI directly or keep strict off.
Thanks
I guess i will go with WMI for now. That snippet cleaned up.
Imports System.Management
Public Class CreateRestorePoint
''' <summary>
''' Defines the search query for the ManagementScope path.
''' </summary>
Private Const MANAGEMENT_SCOPE As String = "\\localhost\root\default:SystemRestore"
''' <summary>
''' Attempts to create a new restore point using WMI.
''' </summary>
''' <returns>True if the restore point was created, other wise false.</returns>
''' <remarks>
''' Gets the object containing the input parameters to a method, and then fills in the values and passes the object to the InvokeMethod call.
''' </remarks>
Friend Function CreateRestorePoint() As Boolean
Dim created As Boolean = True
Using wmiQuery As New ManagementClass(New ManagementPath(MANAGEMENT_SCOPE))
Dim query = GetParams(wmiQuery)
Try
wmiQuery.InvokeMethod("CreateRestorePoint", query, Nothing)
Catch ex As ManagementException
created = False
End Try
End Using
Return created
End Function
''' <summary>
''' Sets the ManagementBaseObject parameters.
''' </summary>
''' <param name="wmiQuery"></param>
''' <returns>Returns a ManagementBaseObject representing the list of input parameters for a method.</returns>
''' <remarks>The members of this class enable you to access WMI data using a specific WMI class path.></remarks>
Private Function GetParams(wmiQuery As ManagementClass) As ManagementBaseObject
Dim query = wmiQuery.GetMethodParameters("CreateRestorePoint")
query("Description") = "-CautionSparta"
query("RestorePointType") = 12
query("EventType") = 100
Return query
End Function
End Class
I have a text file containing the properties for a virtual server running on my machine. I would like to be able to edit those properties from a GUI built with VB 2008. The Properties file is pre-generated with default values and I would like to change those values to fit my needs.
The Properties file is formatted as follows:
Item-One=ValueOne
Item-Two=ValueTwo
Item-Three=OtherLongValue
etc.
What I need is to be able to select the property based off it's name (Item-Two) and then remove the original value (which may be unknown) and place in my custom value. Values are String type.
I have already tried two suggestions, but neither achieve my goal.
Attempt1:
System.IO.File.WriteAllText(propName, System.IO.File.ReadAllText(propName).Replace("initial", "final"))
Attempt2:
Dim thefile As String = PropertyFileName
Dim lines() As String = System.IO.File.ReadAllLines(thefile)
lines(28) = "Item-Example=" + myValue
System.IO.File.WriteAllLines(thefile, lines)
Number One does not work because it requires me to know the original value, which I do not.
Number Two "works" but often adds new lines instead of replacing the old.
Here is a class I made. It is also documented which should help with inteliSense. Bellow I added some example of its usage.
SettingManager.vb
''' <summary>
''' Manages Settings which can be loaded and saved to a file specified
''' </summary>
''' <remarks></remarks>
Public Class SettingManager
Private filePath As String
Private prop As New Dictionary(Of String, String)
''' <summary>
''' Create a new SettingManager and loads settings from file specified.
''' If file specified doesnt exist, a new one is created upon save()
''' </summary>
''' <param name="filePath">Setting file to load</param>
''' <remarks></remarks>
Sub New(ByVal filePath As String)
Me.filePath = filePath
If (Not System.IO.File.Exists(filePath)) Then
Return
End If
Using reader As System.IO.StreamReader = New System.IO.StreamReader(filePath)
Dim line As String
line = reader.ReadLine()
'Loop through the lines and add each setting to the dictionary: prop
Do While (Not line Is Nothing)
'Spit the line into setting name and value
Dim tmp(2) As String
tmp = line.Split("=")
Me.AddSetting(tmp(0), tmp(1))
line = reader.ReadLine()
Loop
End Using
End Sub
''' <summary>
''' Get value of specified setting if exists.
''' If setting doesnt exist, KeyNotFound exception is thrown
''' </summary>
''' <param name="name">Name of setting</param>
''' <returns>Value of setting</returns>
Function GetSetting(ByVal name As String) As String
If (Not prop.ContainsKey(name)) Then
Throw New KeyNotFoundException("Setting: " + name + " not found")
End If
Return prop(name)
End Function
''' <summary>
''' Adds a new setting.
''' </summary>
''' <param name="name">Name of setting</param>
''' <param name="value">Value of setting</param>
''' <remarks>Save() function should be called to save changes</remarks>
Sub AddSetting(ByVal name As String, ByVal value As String)
If (prop.ContainsKey(name)) Then
prop(name) = value
Else
prop.Add(name, value)
End If
End Sub
''' <summary>
''' Saves settings to file. Any new settings added are also saved
''' </summary>
''' <remarks></remarks>
Sub Save()
Using writer As System.IO.StreamWriter = New System.IO.StreamWriter(filePath)
For Each kvp As KeyValuePair(Of String, String) In Me.prop
writer.WriteLine(kvp.Key + "=" + kvp.Value)
Next
End Using
End Sub
End Class
How to use:
Create a new file in your project called SettingManager.vb
Copy the code above into it
Example Usage
Dim sm As New SettingManager("settings.txt")
'Get Setting
Console.WriteLine(sm.GetSetting("Item-One")) 'Value-One
'Change setting
pm.AddSetting("Item-One", "different_value")
Console.WriteLine(sm.GetSetting("Item-One")) 'different_value
'Add new Setting
pm.AddSetting("name", "Krimson")
Console.WriteLine(sm.GetSetting("name")) 'Krimson
'Save any changes made
sm.Save()
Note: The code is not robust enough. For example if a value contains an =, errors might occur since there is no check implemented to prevent this. However, this should be a good starting point
A little Addition
Do While (Not line Is Nothing)
If line = Nothing OrElse line.Length = 0 OrElse line.StartsWith("#") Then
'Continue Do
Else
'Spit the line into setting name and value
Dim tmp(2) As String
tmp = line.Split("=")
Me.AddSetting(tmp(0), tmp(1))
End If
line = reader.ReadLine()
Loop
I'm hoping to improve the performance of the below as well as return the GUID of each user.
I've converted and modified the code found here for searching through groups recursively to get all the members and their details and adding them to a class collection. However I also need to capture the user's managers details so I'm calling the AD twice for each user. This doesn't seem efficient as many of the users will have the same manager. It would seem logical to get the distinct manager details from the collection class and call only these, then replace them wherever they occur in the collection. I don't know the best way to do this however - still fairly new to all this ;)
I'd also like to be able to get the user's GUID, I've tried accessing it directly as a property of the collection, but it doesn't return anything.
Here's my code, I'd really appreciate any comments/suggestions :) - or any bad habits I have in general pointing out! ;)
I'm using vs2005 and .Net 2.0
Public Class ADCLass
''' <summary>
''' Calls recursive function to return users in group
''' </summary>
''' <param name="DistListAlias">CN for the Group</param>
''' <returns>Collection of class holding user details</returns>
''' <remarks></remarks>
Public Function GetDistListUsers(ByVal DistListAlias As String) As Collection(Of ADMembers)
Dim path As String = "LDAP://DC=systems,DC=Private"
Dim filter As String
Dim filterFormat As String = "(cn={0})"
Dim sAMAccountFilter As String
filter = String.Format(filterFormat, DistListAlias)
Dim properties As PropertyCollection = GetPropertiesForEntry(path, filter)
sAMAccountFilter = "(|(ObjectClass=Group)(objectCategory=user))"
Dim groupMembers As Collection(Of ADMembers) = New Collection(Of ADMembers)
If Not IsNothing(properties) Then
Dim sAMAccountTypes As Collection(Of Integer) = New Collection(Of Integer)
groupMembers = GetUsersInGroup(properties, groupMembers, sAMAccountFilter)
End If
Return groupMembers
End Function
#Region "GetUsersInGroup"
''' <summary>
''' Recursive function to list all users in group and sub group
''' Returns the sAMAccountName for the Managers
''' </summary>
''' <param name="Properties">Group Properties</param>
''' <param name="groupMembers">Collection fo Users</param>
''' <param name="filter"></param>
''' <returns>Collection of class holding user details</returns>
''' <remarks></remarks>
Private Function GetUsersInGroup(ByVal Properties As PropertyCollection, ByVal groupMembers As Collection(Of ADMembers), ByVal filter As String)
Dim pathFormat As String = "LDAP://{0}"
Dim memberIdx As String = "member"
Dim sAMAccountNameIdx As String = "sAMAccountName"
Dim sAMAccountTypeIdx As String = "sAMAccountType"
Dim personnelNumberIdx As String = "extensionAttribute4"
Dim TelNo As String
Dim prop As Object
Dim managerID As String
Dim manColl As PropertyCollection
If Not IsNothing(Properties(memberIdx)) Then
'Loop through found Members
For Each prop In Properties(memberIdx)
Dim distinguishedName As String = prop.ToString
Dim path As String = String.Format(pathFormat, distinguishedName)
Dim childProperties As PropertyCollection = GetPropertiesForEntry(path, filter)
If Not IsNothing(childProperties) Then
'Check that this is a user
If childProperties(sAMAccountTypeIdx).Value = 805306368 Then
'GetManager ID
managerID = childProperties("manager").Value.ToString
manColl = GetPropertiesForEntry(String.Format(pathFormat, managerID), filter)
managerID = manColl(sAMAccountNameIdx).Value.ToString
'Get Phone Number, if telephone number is null, check mobile, if null
'return ""
If Not IsNothing(childProperties("telephoneNumber").Value) Then
TelNo = childProperties("telephoneNumber").Value.ToString
Else
If Not IsNothing(childProperties("mobile").Value) Then
TelNo = childProperties("mobile").Value.ToString
Else
TelNo = ""
End If
End If
'Add the Properties to the class collection
groupMembers.Add(New ADMembers(childProperties(sAMAccountNameIdx).Value.ToString, _
childProperties("cn").Value.ToString, _
managerID, _
childProperties("Title").Value.ToString, _
TelNo, _
childProperties("mail").Value.ToString))
Else
'Found a group - recurse
GetUsersInGroup(childProperties, groupMembers, filter)
End If
End If
Next
End If
Return groupMembers
End Function
#End Region
#Region "GetPropertiesForEntry"
''' <summary>
''' Gets properties for given user in AD
''' </summary>
''' <param name="path">Distinguished AD name</param>
''' <param name="filter"></param>
''' <returns>Property collection for given user</returns>
''' <remarks></remarks>
Private Function GetPropertiesForEntry(ByVal path As String, ByVal filter As String) As PropertyCollection
Dim rootEntry As New DirectoryEntry(path)
Dim searcher As New DirectorySearcher(rootEntry)
With searcher
.Filter = filter
.PageSize = 5
.ServerTimeLimit = New TimeSpan(0, 0, 30)
.ClientTimeout = New TimeSpan(0, 10, 0)
End With
Dim result As SearchResult = searcher.FindOne
Return result.GetDirectoryEntry.Properties
End Function
#End Region
End Class
Code I am using as per JPBlancs's suggestion, whilst this works, it is much slower than my original, am I implementing it incorreclty?
Public Sub GetPropertiesForEntry()
Dim rootEntry As New DirectoryEntry("LDAP://DC=d1,DC=d2")
Dim searcher As New DirectorySearcher(rootEntry)
With searcher
.Filter = "(&(memberof:1.2.840.113556.1.4.1941:=CN=grp1,OU=Messaging Groups,OU=Groups,DC=d1,DC=d2)(objectCategory=user))"
.SearchScope = SearchScope.Subtree
.PropertiesToLoad.Add("cn")
.PageSize = 100
.ServerTimeLimit = New TimeSpan(0, 0, 30)
.ClientTimeout = New TimeSpan(0, 10, 0)
End With
Dim results As SearchResultCollection = searcher.FindAll()
For Each result As SearchResult In results
Debug.Print(result.Properties("cn").Item(0).ToString)
Next
End Sub
Can you have a look to Finding users that are members of two active directory groups. You'll find a method using LDAP_MATCHING_RULE_IN_CHAIN to collect recursively users from a group in one query.
As far as th GUID is concerned don't forget list the attribute you want the query to return. Be careful, as far as I remember the GUID will return in an INT array.
dsLookFor.PropertiesToLoad.Add("objectGUID")