Assigning Field-Symbol from table with several conditions and deeper structure - abap

I want to get the line where segnam = 'E1IDB02' and sdata starting with BB (-> sdata has a deeper structure. Therefore sdata has the type of the segnam. Thus means for the example further down, the first to rows have the type E1IDB02 and sdata in the third row has the type E1IDKU3. This will be clearer if you see the example coding further down) and then update a field in the structure in sdata.
For example I have following t_edidd-table:
segnam
sdata
E1IDB02
BA 123456 ...
E1IDB02
BB 987654 ...
E1IDKU3
...
One working solution:
FIELD-SYMBOLS: <ls_e1idb02> TYPE e1idb02.
LOOP AT t_edidd ASSIGNING FIELD-SYMBOL(<lv_edidd>) WHERE segnam = 'E1IDB02' AND sdata(2) = 'BB'.
ASSIGN <lv_edidd>-sdata TO <ls_e1idb02> CASTING.
<ls_e1idb02>-fiibkont = `01`.
ENDLOOP.
Or to be a little bit more clear:
FIELD-SYMBOLS: <ls_e1idb02> TYPE e1idb02.
LOOP AT t_edidd ASSIGNING FIELD-SYMBOL(<lv_edidd>) WHERE segnam = 'E1IDB02'.
ASSIGN <lv_edidd>-sdata TO <ls_e1idb02> CASTING.
IF <ls_e1idb02>-fiiquali = 'BB'. "<----
<ls_e1idb02>-fiibkont = `01`.
ENDIF.
ENDLOOP.
I wonder if there is a better solution for this?
What I have in mind is something like this (not working!):
FIELD-SYMBOLS: <ls_e1idb02> TYPE e1idb02.
ASSIGN t_edidd[ segnam = 'E1IDB02' sdata-fiiquali = 'BB' ]-sdata TO <ls_e1idb02> CASTING.
<ls_e1idb02>-fiibkont = `01`.
ASSIGN t_edidd[ segnam = 'E1IDB02' ]-sdata TO <result> CASTING. would work if I only have one entry with segnam = 'E1IDB02' but I need a second condition for sdata starting with BB or sdata field fiiquali of the structure E1IDB02.
What is working is following:
ASSIGN t_edidd[ segnam = 'E1IDB02' sdata(2) = 'BB' ]-sdata TO <ls_e1idb02> CASTING.
<ls_e1idb02>-fiibkont = `01`.
But due I want to cast the type of sdata into the structure e1idb02 getting the first 2 digits of sdata is not intentional in my opinion.
Hope my problem was understandable. If there is any information missing please let me know.
If someone wants to try this by themself I also wrote a unit test for my problem:
METHOD test.
DATA: ls_e1idb02 TYPE e1idb02,
ls_edidd TYPE edidd,
t_edidd TYPE TABLE OF edidd,
t_edidd_exp TYPE TABLE OF edidd.
ls_edidd-segnam = 'E1IDB02'.
ls_e1idb02-fiiquali = 'BA'.
ls_edidd-sdata = ls_e1idb02.
APPEND ls_edidd TO t_edidd.
APPEND ls_edidd TO t_edidd_exp.
ls_edidd-segnam = 'E1IDB02'.
ls_e1idb02-fiiquali = 'BB'.
ls_edidd-sdata = ls_e1idb02.
APPEND ls_edidd TO t_edidd.
ls_e1idb02-fiibkont = `01`.
ls_edidd-sdata = ls_e1idb02.
APPEND ls_edidd TO t_edidd_exp.
zclass->test(
CHANGING
t_edidd = t_edidd
).
cl_abap_unit_assert=>assert_equals(
act = t_edidd
exp = t_edidd_exp
).
ENDMETHOD.

Related

Variable in function needs to be in single quotes

I am using DataTable.Select() in VB.Net and the in the argument I need single quotes. For example:
DataTable.Select("column = 'value'")
But I want value to be a variable.
I have tried:
DataTable.Select("column = " + var ) Produces error column [var] not found
DataTable.Select("column = '" + var + "'") Produces IndexOutOfBoundsException
DataTable.Select("column = 'actual value'") Works
When using the actual value the variable holds instead of the variable it works so it must be something with the single quotes and concatenation of the variable.
There is no DataSet.Select method. There is a DataTable.Select method (documentation). I'm going to assume that you are referring to it in my answer.
Your 2nd example should work. If it is not then you will need to setup a breakpoint, inspect the value being passed to the Select method, and verify that it matches up with what you are expecting.
I would make one change and that is to use String interpolation or String.Format. This helps the code's readability.
This is a working example:
' create/seed the table
Dim table = New DataTable("Table1")
Dim column = New DataColumn("Column1")
table.Columns.Add(column)
For index = 1 To 10
table.Rows.Add({"Cell" & index.ToString()})
Next
' get value
Dim value = "Cell1"
Dim hardcodedValue = table.Select("Column1 = 'Cell1'")
Console.WriteLine(hardcodedValue(0)(0))
Dim variableValue = table.Select(String.Format("Column1 = '{0}'", value))
Console.WriteLine(variableValue(0)(0))
Fiddle: https://dotnetfiddle.net/7kZpY5

Is it possibile to include Sub inside the user-Type in openoffice? VBA

User-Type is the kind of structure. I'm wondering if i can have sub delaration inside it. Something like:
Type myType
myParam1 As String
myParam2 As Long
...
Sub mySub(param)
'here I want some code for printing/showing params value
End Sub
End Type
I ask because i have problem with printing value of the myParam, when data are in an array of items of myType. After populating myArr with myType items, statment
print myArr(i).myParam1
gives me empty string.
In order to create an array of a declared type, be sure to use the Dim As New syntax.
Type myType
myParam1 As String
myParam2 As Long
End Type
Sub mySub
Dim myArr(2) As New myType
myArr(0).myParam1 = "A"
myArr(0).myParam2 = 1
myArr(1).myParam1 = "B"
myArr(1).myParam2 = 2
For i = 0 to Ubound(myArr) - 1
Print myArr(i).myParam1
Next
End Sub
As for adding subroutines in a Type statement, it is not in the documentation. On the other hand, that's an integral part of Python, one of the most popular LibreOffice scripting languages.
class myClass:
myAttr1 = ""
myAttr2 = 0
def myFunc(self, param):
self.myAttr2 = param
print(self.myAttr1)
myArr = [myClass(), myClass()]
myArr[0].myAttr1 = "A"
myArr[0].myAttr2 = 1
myArr[1].myAttr1 = "B"
myArr[1].myAttr2 = 2
for myObj in myArr:
myObj.myFunc(3)

How to get CType/DirectCast working with a defined variable instead of a direct type?

I can't get the code below working.
The error is in the last line: Type 'ChangeType' is not defined.
Does the compiler thinks that ChangeType is a customtype which i did't have defiened ?
I have no clue, plz give me a hint.
May be I can't see the forest for the trees.
Dim DataValue as String = "True"
Dim ChangeTypeIndex() As String = {"System.Boolean", "System.Char", "System.SByte", "System.Byte", "System.Int16"}
Dim ChangeType As Type = Type.GetType(ChangeTypeIndex(0))
Dim Result = DirectCast(DataValue, ChangeType)
This is not possible in VB.NET. VB.NET is a type-safe language, and the express purpose of DirectCast is to aid in the compile-time type checking. Since it is analyzed for correctness at compile-time, it, by definition, can't be given a variable for the type. DirectCast can only be used to cast an object to another directly-related type (by inheritance or implementation). Since DataValue is a String, you couldn't cast it to a Boolean anyway (since String doesn't inherit from Boolean), even if DirectCast did allow you to pass a variable type like that.
.NET does support reflection and late-binding, so it is possible to do the same kind of thing, if you really need to, but it's generally a good idea to avoid these kinds of things as much as you can, so as to ensure that you are getting the most benefit out of the compiler's type-checking safety measures.
Warnings aside, if you really need to do this, a close approximation would be something like this:
Option Strict Off
' ...
Dim dataValue As String = "True"
Dim changeTypeIndex() As String = {"System.Boolean", "System.Char", "System.SByte", "System.Byte", "System.Int16"}
Dim changeType As Type = Type.GetType(changeTypeIndex(0))
Dim o As Object = Activator.CreateInstance(changeType)
Dim result As Object = o.Parse(dataValue)
Console.WriteLine(result.GetType().Name) ' Outputs "Boolean"
Console.WriteLine(result) ' Outputs "True"
Not sure what you are trying to do, but here is some code to play with. Note that I have changed the 'types' in the array to contain valid type names.
Dim DataValue As String = "True"
Dim ChangeTypeIndex() As String = {"System.Boolean", "System.Char", "System.SByte", "System.Byte", "System.Int16"}
Dim ChangeType As Type
For x As Integer = 0 To ChangeTypeIndex.Length - 1
ChangeType = Type.GetType(ChangeTypeIndex(x), True)
Next
ChangeType = Type.GetType(ChangeTypeIndex(0), True)
Dim Result As Object = CTypeDynamic(DataValue, ChangeType)

Data dictionary object check with rs_dd_check

rs_dd_check is a great function to check ddic objects. But the function module does not fit me that i can call it directly because i need to use it on older systems which only have the dialog and you can not export the messages out of the fm.
so i extracted some code out of it (out of perform check_object subroutine) which should be sufficient, and it is, for tables and structures it works!!! But for every other element it's not working. :(
Basically im creating a log and then doing check and then importing from memory id 'CHE' for example CHETABLSFLIGHT into variable/table lt_log
Im sure that for other elements it is creating logs but im not sure if it fill them up...Because lt_log stays empty.
report report name.
data: objname type rsedd0-ddobjname value 'object_name', eg sflighs
eutype type rsdxx-eutype value 'object_type', eg T
enqtype type rsdeo-objtype,
protid type sy-tabix,
titletxt TYPE sprot_i-prot,
actmode TYPE ddrefstruc-mode VALUE 9,
act_res type STANDARD TABLE OF dctablres,
lt_log type STANDARD TABLE OF trlogm .
*TRANSLATE T INTO TABL ETC
call function 'INTERN_TRANSL_EUTYPE' "Sperrtyp
exporting
eutype = eutype
importing
enqueue_type = enqtype.
*CREATING LOG?
call function 'DD_OBJ_PROT_OPEN'
exporting
objectname = objname
objecttype = enqtype
level = 1
device = 'M' "Memory with report RSPUTPRT as frontend
ddfunc = 'CHE'
importing
prid = protid
exceptions
others = 01.
*CHECKING SYNTAX
case eutype .
when 'T'.
titletxt = 'CHECKING TABLES'.
call function 'DD_TABL_ACT'
exporting
device = 'M'
path = ' '
tabname = objname
timer_on = ' '
prid = protid
act_mode = actmode
protname = ''
tables
act_res_tab = act_res
exceptions
others = 03. "Abbruch -> Protokoll anzeigen
when 'V'. "View
titletxt = 'CHECKING VIEWS'.
call function 'DD_VIEW_ACT'
exporting
viewname = objname
get_state = 'M'
act_mode = actmode
prid = protid
protname = ''
exceptions
others = 03.
when others.
endcase.
TRANSLATE OBJNAME USING '/-\-'.
data lv_mem_id(200) type c.
CONCATENATE 'CHE' enqtype objname into lv_mem_id. "EX CHETABLTABLE_NAME
IMPORT lt_log FROM MEMORY ID lv_mem_id.

Values in list of structures don't change

I have defined a structure in my code and have a list of this structures"
Structure Parcel
Public name As String
Public type As String
End Structure
Dim ParcelList As New List(Of Parcel)
Then I'm trying to set some values to an element of the list which name is known to me
For Each myParcel As Parcel In ParcelList
If (myParcel.name = "Parcel1") Then
myParcel.type="Type1"
End If
Next
Unfortunately values in my list don't change at all. what am I doing wrong?
As Parcel is a Structure, it is passed by value so when iterating through collection, you are modifying a copy of your structure.
To better understand this case, you should understand what For Each really is. Your code can be translated into:
Dim enumerator As List(Of Parcel).Enumerator = ParcelList.GetEnumerator()
While enumerator.MoveNext()
' Here you have a local copy of your Structure
Dim myParcel As Parcel = enumerator.Current
Dim flag As Boolean = Operators.CompareString(myParcel.name, "Parcel1", False) = 0
If flag Then
' Here you modify your local copy
myParcel.type = "Type1"
End If
End While
If Parcel was a Class, it would be passed by reference so no local copy would be created and line myParcel.type = "Type1" would change proper object existing in your collection.
As already Stated this is because you are modifying a local copy of a value type. One way round this is to access the items in the list by ordinal and replace the ordinal value type with a new type:
For i As Integer = 0 To ParcelList.Count - 1
If ParcelList(i).name = "Parcel1" Then
ParcelList(i) = New Parcel With {.name = ParcelList(i).name, .type = "Type1"}
End If
Next
But really you should change the Sturcture to a Class
When checking for strings use Equals instead of '='.
If (myParcel.name.equals("Parcel1")) Then
myParcel.type="Type1"
End If
Strings are in fact 'Objects'. When you compare Strings (example StringA = StringB), you check the allocation of the String in Memory instead of the contents of the string.
Even better would be:
If (myParcel.name.ToUpper().equals(Cstr("Parcel1").toUpper())) Then
myParcel.type="Type1"
End If
That way you ignore any difference case-wise.
example:
myParcel.name = "teST"
myParcel.name.equals("test")
is False
myParcel.name.ToUpper().equals(Cstr("test").toUpper())
is true