如何解决集合列表清空自身
我有一个类,用于向继承 System.Collections.CollectionBase
的数据库 (PostgreSQL) 连接对象添加参数。此类位于我用于多个应用程序的公共库中。通常,它会毫无问题地添加对象,但我开始遇到一个奇怪的问题,即集合无缘无故地清空其对象。这会导致 SQL 语句未正确构建的错误。
环境
- Windows 10 专业版 x64 (19042.804)
- Visual Studio 2017 CE (4.8.0484)
- .NET Framework 4.7.2(库和应用程序)
- PostgreSQL 服务器 v12.1
- Npgsql 5.0.3(见下文)
故障排除
这是发生问题的(混淆)代码:
SQLCommand = "INSERT INTO table" & vbCrLf
SQLCommand += "(" & vbCrLf
SQLCommand += vbTab & "column1," & vbCrLf
SQLCommand += vbTab & "column2," & vbCrLf
SQLCommand += vbTab & "column3," & vbCrLf
SQLCommand += vbTab & "column4," & vbCrLf
SQLCommand += vbTab & "column5," & vbCrLf
SQLCommand += vbTab & "column6," & vbCrLf
SQLCommand += vbTab & "column7," & vbCrLf
SQLCommand += vbTab & "column8," & vbCrLf
SQLCommand += vbTab & "column9," & vbCrLf
SQLCommand += vbTab & "column10" & vbCrLf
SQLCommand += ")" & vbCrLf
SQLCommand += "VALUES" & vbCrLf
SQLCommand += "(" & vbCrLf
SQLCommand += vbTab & ":parameter1," & vbCrLf
SQLCommand += vbTab & ":parameter2," & vbCrLf
SQLCommand += vbTab & ":parameter3," & vbCrLf
SQLCommand += vbTab & ":parameter4," & vbCrLf
SQLCommand += vbTab & ":parameter5," & vbCrLf
SQLCommand += vbTab & ":parameter6," & vbCrLf
SQLCommand += vbTab & ":parameter7," & vbCrLf
SQLCommand += vbTab & ":parameter8," & vbCrLf
SQLCommand += vbTab & ":parameter9," & vbCrLf
SQLCommand += vbTab & ":parameter10" & vbCrLf
SQLCommand += ")" & vbCrLf
SQLCommand += "RETURNING pkid"
PGDB.Parameters.Add(":parameter1",value1) 'String
PGDB.Parameters.Add(":parameter2",value2) 'String
PGDB.Parameters.Add(":parameter3",value3) 'String
PGDB.Parameters.Add(":parameter4",value4) 'String
PGDB.Parameters.Add(":parameter5",value5) 'String
PGDB.Parameters.Add(":parameter6",value6) 'String
PGDB.Parameters.Add(":parameter7",value7) 'String - THIS IS WHERE THE LIST CLEARS
PGDB.Parameters.Add(":parameter8",value8) 'Boolean
PGDB.Parameters.Add(":parameter9",value9) 'String
PGDB.Parameters.Add(":parameter10",value10) 'String
MyID = Convert.ToInt32(PGDB.ExecuteStatementScalar(SQLCommand))
PGDB
对象是我的 Npgsql
数据库连接对象,Parameters
对象是继承的集合。前六个参数添加到集合中没有问题,但是一旦添加第七个参数,整个列表就会清空自己并重新开始。正在执行的 SQL 语句应该如下所示:
-- EXPECTED SQL - WHAT IS STORED IN THE SQLCommand VARIABLE
INSERT INTO table
(
column1,column2,column3,column4,column5,column6,column7,column8,column9,column10
)
VALUES
(
:parameter1,:parameter2,:parameter3,:parameter4,:parameter5,:parameter6,:parameter7,:parameter8,:parameter9,:parameter10
)
RETURNING pkid
...但是,我得到的是:
-- ACTUAL (WRONG) SQL EXECUTED BY THE DATABASE
INSERT INTO table
(
column1,$1,$2,$3,$4
)
RETURNING pkid
...然后在它实际尝试执行 SQL 语句时生成一个 Npgsql.PostgresException
抱怨语法:
42601: syntax error at or near ":"
我已经设置了断点来逐步完成该过程,但它始终是相同的行为。以下是我的 IDE 中的一些屏幕截图:
这是在添加第一个参数之前 Parameters
集合对象的样子:
这是当它进入对第七个参数的 Add()
方法的执行时的样子:
可以肯定的是,我还检查了第六个参数上 Add()
方法进入执行时的状态:
这种方法一次运行没有错误,所以我不确定为什么它“突然”停止工作。为了解决此问题并使所有参数正确加载,我将 Npgsql
库从版本 4.1.8 升级到 5.0.3。在我与它斗争了一段时间后 - 我不得不解决与 System.Buffers
库的一些版本冲突 - 我能够让它再次运行,但不幸的是,我得到了完全相同的结果.
以防万一它可能是内存问题,我继续关闭所有东西并重新启动计算机。这也没有解决问题。
作为参考,这里是 PGSQLParameters
类的精简版本,不包括不同值类型的各种重载。
Imports Npgsql
#Region "POSTGRESQL PARAMETER COLLECTION OBJECT"
Public Class PGSQLParameters
Inherits System.Collections.CollectionBase
Public Enum SQLDecimalType
SQLMoney = 1
SQLDecimal = 2
End Enum
#Region "COLLECTION ADD AND SUPPORT METHODS"
#Region "PUBLIC METHODS FOR ADDING ITEMS TO THE COLLECTION"
'-- Input Parameter
Public Overloads Sub Add(ByVal ParameterName As String,ByVal DataType As DbType,ByVal Size As Int32,ByVal Value As Object)
If ParameterName.Length = 0 Then
Return
End If
If TypeOf (Value) Is String AndAlso String.IsNullOrEmpty(Convert.ToString(Value)) Then
Value = DBNull.Value
End If
If Not ParameterName.StartsWith(":") Then
ParameterName = ParameterName.Insert(0,":")
End If
List.Add(BuildParameter(ParameterName,DataType,Size,ParameterDirection.Input,Value))
End Sub
#Region "INPUT OVERLOADS"
'-- String
Public Overloads Sub Add(ByVal ParameterName As String,ByVal Value As String)
Dim StringLength As Integer = 0
If Not Value = Nothing AndAlso Not String.IsNullOrEmpty(Value) Then
StringLength = Value.Length
End If
Add(ParameterName,DbType.String,StringLength,Value)
End Sub
#End Region
#End Region
Private Function BuildParameter(ByVal ParameterName As String,ByVal Direction As ParameterDirection,ByVal Value As Object) As NpgsqlParameter
Dim NewParameter As NpgsqlParameter
If Size > 0 Then
NewParameter = New NpgsqlParameter(ParameterName,Size)
Else
NewParameter = New NpgsqlParameter(ParameterName,DataType)
End If
NewParameter.Direction = Direction
If Not (Direction = ParameterDirection.Output AndAlso Value Is Nothing) Then
NewParameter.Value = DBNull.Value
If Not Value Is Nothing Then
NewParameter.Value = Value
ElseIf TypeOf (Value) Is Boolean Then
NewParameter.Value = Value
End If
End If
Return NewParameter
End Function
#End Region
End Class
#End Region
我看不出有任何理由对 Parameters
集合进行这种自发的“清除”,特别是因为导致并包括“问题”的所有参数都是 String
值,因此它们'都使用完全相同的方法调用(我已经在我的演练中确认了这一点)。此外,根据正在执行的 SQL,它看起来实际上以某种方式保留集合对象中的前六个参数,只是不添加新参数,这完全没有意义.
此外,它看起来并没有完全重新实例化对象,因为如屏幕截图所示,Capacity
不会从第六个参数更改为第七个参数。如果我不得不说的话,它看起来像是在添加六个参数后克隆集合,然后丢弃该克隆和/或完全忽略它。再说一次,这对我来说毫无意义。
我不怀疑我只是忽略了某些东西,但我不知道那个“东西”是什么。有没有其他人遇到过这种行为?任何帮助或想法将不胜感激。如果我可以或需要提供任何其他详细信息,请告诉我。
解决方法
可能需要发布更多代码 - 发布的代码对我来说似乎没有任何问题:
将此图标拖到您的桌面上,将其重命名为 .zip 并打开它:
它有我用来检查您的问题的确切解决方案文件(它没有在我的计算机上显示问题)
,我已经设法解决了这个问题,但原因是我没有预料到的,如果没有完整的更多代码列表,原因可能不会很明显。我很抱歉没有在原始问题中提供足够的细节,但我没有猜到我最终会在哪里找到问题的原因。
正如我上面指出的,问题总是出现在序列中的相同参数上。我试图分配给该特定参数的值是另一个类中 String
对象的公共属性 (Lazy(Of T)
)。
有问题的对象看起来像这样:
#Region "REAL ESTATE OBJECT"
''' <summary>
''' Standard object containing details about a specific piece of real estate
''' </summary>
Public Class RealEstate
#Region "PRIVATE FIELDS"
<EditorBrowsable(EditorBrowsableState.Never)> <DebuggerBrowsable(DebuggerBrowsableState.Never)>
Private _RealEstateTypeCode As String
<EditorBrowsable(EditorBrowsableState.Never)> <DebuggerBrowsable(DebuggerBrowsableState.Never)>
Private _PhysicalStreet1 As String
<EditorBrowsable(EditorBrowsableState.Never)> <DebuggerBrowsable(DebuggerBrowsableState.Never)>
Private _PhysicalStreet2 As String
<EditorBrowsable(EditorBrowsableState.Never)> <DebuggerBrowsable(DebuggerBrowsableState.Never)>
Private _PhysicalCity As String
<EditorBrowsable(EditorBrowsableState.Never)> <DebuggerBrowsable(DebuggerBrowsableState.Never)>
Private _PhysicalState As String
<EditorBrowsable(EditorBrowsableState.Never)> <DebuggerBrowsable(DebuggerBrowsableState.Never)>
Private _PhysicalZIPCode As String
#End Region
#Region "PRIVATE PROPERTIES"
<EditorBrowsable(EditorBrowsableState.Never)> <DebuggerBrowsable(DebuggerBrowsableState.Never)>
Private Property PGDB As PGSQLDB
#Region "LAZY PROPERTIES"
' >> THIS IS THE PROPERTY THAT APPEARS TO HAVE CAUSED THE ISSUE <<
<EditorBrowsable(EditorBrowsableState.Never)> <DebuggerBrowsable(DebuggerBrowsableState.Never)>
Private Property _RealEstateType As Lazy(Of PropertyType) =
New Lazy(Of PropertyType)(Function()
Return New PropertyType(_RealEstateTypeCode,Me.CIADB)
End Function)
#End Region
#End Region
#Region "PUBLIC PROPERTIES"
Public Property RealEstateID As Integer
Public Property PhysicalStreet1 As String
Get
Return _PhysicalStreet1
End Get
Set(value As String)
If Not value Is Nothing Then
If value.Trim.Length > 120 Then
_PhysicalStreet1 = value.Trim.Substring(0,120).Trim.ToUpper
Else
_PhysicalStreet1 = value.Trim.ToUpper
End If
Else
_PhysicalStreet1 = String.Empty
End If
End Set
End Property
Public Property PhysicalStreet2 As String
Get
Return _PhysicalStreet2
End Get
Set(value As String)
If Not value Is Nothing Then
If value.Trim.Length > 120 Then
_PhysicalStreet2 = value.Trim.Substring(0,120).Trim.ToUpper
Else
_PhysicalStreet2 = value.Trim.ToUpper
End If
Else
_PhysicalStreet2 = String.Empty
End If
End Set
End Property
Public Property PhysicalCity As String
Get
Return _PhysicalCity
End Get
Set(value As String)
If Not value Is Nothing Then
If value.Trim.Length > 60 Then
_PhysicalCity = value.Trim.Substring(0,60).Trim.ToUpper
Else
_PhysicalCity = value.Trim.ToUpper
End If
Else
_PhysicalCity = String.Empty
End If
End Set
End Property
Public Property PhysicalState As String
Get
If _PhysicalState Is Nothing OrElse String.IsNullOrEmpty(_PhysicalState) OrElse _PhysicalState = "XX" Then
If Not _PhysicalZIPCode Is Nothing AndAlso Not String.IsNullOrEmpty(_PhysicalZIPCode) Then
_PhysicalState = Utility.GetStateCodeFromZIP(_PhysicalZIPCode)
End If
End If
Return _PhysicalState
End Get
Set(value As String)
If Not value Is Nothing Then
If value.Trim.Length > 2 Then
_PhysicalState = Utility.GetStateCodeFromName(value.Trim)
Else
If [Enum].IsDefined(GetType(USState),value.Trim.ToUpper) Then
Dim PState As USState
If [Enum].TryParse(value.Trim.ToUpper,PState) Then
_PhysicalState = Utility.GetStateCodeFromName(PState.GetEnumDescription)
End If
Else
_PhysicalState = value.Trim.ToUpper
End If
End If
Else
_PhysicalState = "OK"
End If
End Set
End Property
Public Property PhysicalZIPCode As String
Get
Return _PhysicalZIPCode
End Get
Set(value As String)
If Not value Is Nothing Then
If value.Trim.Length > 10 Then
_PhysicalZIPCode = value.Trim.Substring(0,10).Trim.ToUpper
Else
_PhysicalZIPCode = value.Trim.ToUpper
End If
Else
_PhysicalZIPCode = String.Empty
End If
End Set
End Property
Public WriteOnly Property RealEstateTypeCode As String
Set(value As String)
_RealEstateTypeCode = value
End Set
End Property
Public ReadOnly Property RealEstateType As PropertyType
Get
Return _RealEstateType.Value
End Get
End Property
#End Region
在我的原始混淆代码中,我只是注入了一个通用字符串作为占位符,但问题似乎与此特定分配有关。添加到参数列表的其他值是可立即访问的对象的“常规”属性。但是,在使用 Add()
参数的 Lazy(Of T)
对象调用 Value
方法时,某些东西似乎“短路”了。
为了“修复”这个问题,我声明了一个额外的本地 String
变量,用于从这个 Lazy(Of T)
对象中检索所需属性的值。然后我使用 局部变量 来分配给 Add()
方法的 Value
参数:
With REObject 'A RealEstate object
' > DECLARING THIS LOCAL VARIABLE TO RETRIEVE THE VALUE OF THE LAZY PROPERTY
Dim TypeCode As String = .RealEstateType.TypeCode
...
PGDB.Parameters.Add("street1",.PhysicalStreet1)
PGDB.Parameters.Add("street2",.PhysicalStreet2)
PGDB.Parameters.Add("city",.PhysicalCity)
PGDB.Parameters.Add("state",.PhysicalState)
PGDB.Parameters.Add("zip",.PhysicalZIPCode)
' > CHANGED THE FOLLOWING
' PGDB.Parameters.Add("type",.RealEstateType.TypeCode) 'String - THIS IS WHERE THE LIST CLEARS
' > TO USE THE LOCAL VARIABLE INSTEAD OF THE LAZY OBJECT'S PROPERTY VALUE
PGDB.Parameters.Add("type",TypeCode)
' > THE VALUE IS NOW SUCCESSFULLY ADDED
...
End With
执行这段代码会导致所有参数正确填充正确的值,并且在数据库中执行的 SQL 语句没有错误。因此,似乎 Lazy(Of T)
对象尚未“填充”这一事实在进入 {{1} } 方法。老实说,我仍然不确定为什么它在尝试使用 Add()
对象的属性时“重置”了 .List
对象的 Collection
属性值,但至少这个分辨率达到了预期的目标。同样,我很抱歉最初没有提供足够的细节,但希望这会对其他人有所帮助。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。