I've recently started an apprenticeship and I've received a small project to help checking tables.
The request is that I am supposed to write a report that compares a table to our profit center's standard hierarchy and tells you which entries are the same and which ones are not.
Now, I've only started getting into ABAP and while I've had SQL prior, i'm not exactly good in it. My colleagues are nice but I fear that I'd look like an idiot if I kept asking them how to do this.
What i've done so far is giving the table some records to check in our development system, selecting all records in it and also selecting everything I need from SETLEAF and SETNODE.
SELECT * FROM Y_TABLE
INTO TABLE #DATA(lt_compare).
SELECTION-SCREEN BEGIN OF BLOCK set_leaf.
CONSTANTS:
SET_CLASS TYPE SETLEAF-SETCLASS VALUE '0102',
SUB_CLASS TYPE SETLEAF-SUBCLASS VALUE 'D100'.
PARAMETERS:
lv_pcnr TYPE SETLEAF-VALFROM,
setname TYPE SETLEAF-SETNAME.
SELECTION-SCREEN END OF BLOCK set_leaf.
TYPES:
BEGIN OF lt_ausgabe,
SETCLASS TYPE SETLEAF-SETCLASS,
SUBCLASS TYPE SETLEAF-SUBCLASS,
VALFROM TYPE SETLEAF-VALFROM,
SETNAME TYPE SETLEAF-SETNAME,
END OF lt_ausgabe.
DATA:
gt_setleaf TYPE STANDARD TABLE OF lt_ausgabe,
gt_setnode TYPE STANDARD TABLE OF lt_ausgabe.
SETNODE-SUBSETNAME = SETLEAF-SETNAME.
SETNODE-SETNAME = SETNODE-SUBSETNAME.
FORM build_table_setleaf.
SELECT *
FROM SETLEAF
INTO CORRESPONDING FIELDS OF TABLE #gt_setleaf
WHERE SETCLASS = #set_class AND SUBCLASS = #sub_class AND VALFROM = #lv_pcnr AND SETNAME = #setname.
ENDFORM.
FORM build_table_setnode.
SELECT *
FROM SETNODE
INTO CORRESPONDING FIELDS OF TABLE #gt_setnode
WHERE SETCLASS = #set_class AND SUBCLASS = #sub_class AND SUBSETNAME = #setname.
ENDFORM.
I've changed the table name and the constant values because I don't know how much of them I can share.
Now I want to compare these tables and well, do what the request asked for. But I don't really understand how to do this. The code above may not be the way to solve this at all..
I'm sorry in advance if any of this sounds off, I would ask in my own language if.. my people weren't known for being unhelpful and rude when asking code-related stuff.
Thank you in advance.
Related
This my project code I want to save my data into database.
def save(){
List<Employee> list = Employee.findAllById(session.getAttribute("empId"))
Milestone milestone = new Milestone()
milestone.setMilestone_Date(params.milestone_Date)
milestone.setMilestone_Name(params.milestone_Name)
milestone.setMilestone_Description(params.milestone_Description)
milestone.save()
EmployeeMilestone employeeMilestone=new EmployeeMilestone()
Employee employee = list.get(0)
employeeMilestone.setEmployee(employee)
employeeMilestone.setMilestone(milestone)
employeeMilestone.save()
[employeeMilestones:employeeMilestone]
}
I am getting this error
Error 500: Internal Server Error URI /ProjectTrackerMain/milestone/save Class java.lang.IndexOutOfBoundsException Message Index: 0, Size: 0
You didn't actually ask a question, so this may be a bit vague!
An IndexOutOfBoundsException happens when you try to access something from a collection in a location where there is no "something". For example, maybe you asked for the tenth element in a list, but there are only two. In your case, you're asking for the zeroth (in plain English, "First") element on this line of code:
Employee employee = list.get(0)
and presumably the list is empty. Your error message says "Size: 0". You can't get the first element from a list that has zero elements in it, so that's an index out of bounds exception.
Why is your list 0? That's a different question. You might try printing out
session.getAttribute("empId")
to see if your employee ID is what you expected. You might also look at the data in your database to see if you actually managed to save an employee! One way or another, you're not getting the data you expected, and then you're trying to use it.
In general, using a debugger to look at your elements, or just using "println" along the way to look at values is helpful in debugging problems like this. That way, you'll find out on line 1 that your list of Employees is not what you expected, instead of several lines later when you try to use it!
I am new to learning and understanding how Hydration works, just wanted to point that out first. I'm currently able to Hydrate Select and Insert queries without any problems.
I am currently stuck on trying to Hydrate Update queries now. In my entity I have setup the get/set options for each type of column in my database. I've found that the ObjectProperty() Hydrator works best for my situation too.
However whenever I try to update only a set number of columns and extract via the hydrator I am getting errors because all the other options are not set and are returning null values. I do not need to update everything for a particular row, just a few columns.
For example in my DB Table I may have:
name
phone_number
email_address
But I only need to update the phone_number.
$entity_passport = $this->getEntityPassport();
$entity_passport->setPrimaryPhone('5551239876');
$this->getTablePassport()->update($this->getHydrator()->extract($entity_passport), array(
'employeeid' => '1'
));
This returns an error because setName() and setEmailAddress() are not included in this update and the query returns that the values cannot be null. But clearly when you look at the DB Table, there is data already there. The data that is there does not need to be changed either, only in this example does the PrimaryPhone() number.
I've been looking and reading documentation all over the place but I cannot find anything that would explain what I am doing wrong. I should note that I am only using Zend\Db (Not Doctrine).
I'm assuming I've missed something someplace due to my lack of knowledge with this new feature I'm trying to understand.
Perhaps you don't Hydrate Update queries... I'm sort of lost / confused. Any help would be appreciated. Thank you!
I think you're having a fundamental misconception of hydration. A hydrator simply populates an entity object from data (hydrate) and extracts data from an entity object (extract). So there are no separate hydrators for different types of queries.
In your update example you should first retrieve the complete entity object ($entity_passport) and then pass it to the TableGateway's update method. You would retrieve the entity by employeeid, since that's the condition you're using to update. So something like this:
$entity_passport = $passportMapper->findByEmployeeId(1);
$entity_passport->setPrimaryPhone('5551239876');
$this->getTablePassport()->update($this->getHydrator()->extract($entity_passport), array(
'employeeid' => $entity_passport->getId()
));
This is assuming you have some sort of mapper layer. Otherwise you could use your passport TableGateway (I assume that's what getTablePassport() returns, no?).
Otherwise, if you think retrieving the object is too much overhead and you just want to run the query you could use just a \Zend\Db\Sql\Sql object, ie:
$sql = new \Zend\Db\Sql\Sql($dbAdapter);
$update = $sql->update('passport')
->set(array('primary_phone' => $entity_passport->getPrimaryPhone()))
->where(array('employeeid' => $employeeId));
Edit:
Maybe it was a mistake to bring up the mapper, because it may cause more confusion. You could simply use your TableGateway to retrieve the entity object and then hydrate the returned row:
$rows = $this->getTablePassport()->select(array('employeeid' => 1));
$entity_passport = $this->getHydrator($rows->current());
[...]
Edit 2:
I checked your gist and I noticed a few things, so here we go:
I see that your getTablePassport indeed does return an object which is a subclass of TableGateway. You have already set up this class for it to use a HydratingResultset. This means you don't need to do any manual hydrating when retrieving objects using the gateway.
You also already implemented a Search method in that same class, so why not just use that? However I would change that method, because right now you're using LIKE for every single column. Not only is it very inefficient, but it will also give you wrong results, for example on the id column.
If you were to fix that method then you can simply call it in the Service object:
$this->getTablePassport->Search(array('employeeid' => 1));
Otherwise you could just implement a separate method in that tablegateway class, such as
public function findByEmployeeId($employeeId)
{
return $tableGateway->select(array('employeeid' => $employeeId));
}
This should already return an array of entities (or one in this specific case). P.S. make sure to debug and check what is actually being returned when you retrieve the entity. So print_r the entity you get back from the PassportTable before trying the update. You first have to make sure the retrieval code works well.
I am using Mygeneration tools to create the abstract classes responsible for dealing with database to perform CRUD operation as well as some other dooDad operations. Problem is I cant retrieve the auto number field (it is also Primary Key) of table using the code
Employees newObj = new Employees();
newObj.ConnectionString = connectionString;
newObj.AddNew();
// Your Properties will be different here
newObj.FirstName = "Joe";
newObj.LastName = "Plank Plank";
newObj.Save();
int staffid=newObj.StaffID;
The same thing is working fine in MS SQL server or other databases. Looks like auto number is not generated instantly which can be accessed once I added the entry. But, later, when I am checking the database, I found that auto number is generated there. Not sure, why this is happening. Anybody having expertise with dooDads, please help with info.
Edited:
The main problem is I cant access the autonumber field instantly after I create the fresh row entry. Looks like MS Access autonumber takes some time to show up and even in VS, you can see this phenomenon. How to fix this problem?
I have built many applications using Doodads , using MS Access , you have only to make the filed as autonumber .. and generate the stored procedures and other classes.
i.e your code should work ..
also I made modification to Dodads to return list of Objects
How to get list of objects from BusinessEntity using myGeneration?
What is wrong in this code?
I was expected "titi" in person.name but I still have "toto"!
More explicitly, how to modify a record in a function?
init1()->
S=#person{name="toto"}, %record creation and field setting
fct(S),
io:format("~s~n",[S#person.name]).
fct(R)->
R#person{name="titi"}. %record updating
You need to get a result of fct():
init1()->
S=#person{name="toto"}, %record creation and field setting
S2 = fct(S), % Get updated record
io:format("~s~n",[S2#person.name]).
fct(R)->
R#person{name="titi"}. %record updating
Bertaud, I think you are getting ahead of yourself a bit. You really need to understand the basics of immutability before you write any more code. (i.e. "variables" do not vary : you can only assign a value to them once.) I suggest you read the free online guide "Learn You Some Erlang For Great Good", at http://learnyousomeerlang.com/. The section that covers the basics of variables is http://learnyousomeerlang.com/starting-out-for-real#invariable-variables.
It is impossible to stress too much that all data in Erlang is immutable. So to do something like in your original question you need to modify it like #hdima did. The record is not updated but rewritten. In the same way there is no global data in Erlang, all data belongs to a process. This is even true of ETS tables as they basically behave like a process, albeit a built-in one without explicit communication.
So if you use the process dictionary or an ETS table the data itself can never be updated, only the dictionary/table. This means that to modify some data in the dictionary/table you basically have to:
"Read" the data
Update the data making new data
"Write" the new back into the dictionary/table
Without writing the new data back into the dictionary/table it will be lost, as your new data was.
Within fct(), you're not mutating the record, but you're returning a new value for the record, which needs to be used further. If you're calling fct(S), without handling the return value, then you'll lose that new value ("titi").
I'm working on an application at the moment in ASP.NET MVC which has a number of look-up tables, all of the form
LookUp {
Id
Text
}
As you can see, this just maps the Id to a textual value. These are used for things such as Colours. I now have a number of these, currently 6 and probably soon to be more.
I'm trying to put together an API that can be used via AJAX to allow the user to add/list/remove values from these lookup tables, so for example I could have something like:
http://example.com/Attributes/Colours/[List/Add/Delete]
My current problem is that clearly, regardless of which lookup table I'm using, everything else happens exactly the same. So really there should be no repetition of code whatsoever.
I currently have a custom route which points to an 'AttributeController', which figures out the attribute/look-up table in question based upon the URL (ie http://example.com/Attributes/Colours/List would want the 'Colours' table). I pass the attribute (Colours - a string) and the operation (List/Add/Delete), as well as any other parameters required (say "Red" if I want to add red to the list) back to my repository where the actual work is performed.
Things start getting messy here, as at the moment I've resorted to doing a switch/case on the attribute string, which can then grab the Linq-to-Sql entity corresponding to the particular lookup table. I find this pretty dirty though as I find myself having to write the same operations on each of the look-up entities, ugh!
What I'd really like to do is have some sort of mapping, which I could simply pass in the attribute name and get out some form of generic lookup object, which I could perform the desired operations on without having to care about type.
Is there some way to do this to my Linq-To-Sql entities? I've tried making them implement a basic interface (IAttribute), which simply specifies the Id/Text properties, however doing things like this fails:
System.Data.Linq.Table<IAttribute> table = GetAttribute("Colours");
As I cannot convert System.Data.Linq.Table<Colour> to System.Data.Linq.Table<IAttribute>.
Is there a way to make these look-up tables 'generic'?
Apologies that this is a bit of a brain-dump. There's surely imformation missing here, so just let me know if you'd like any further details. Cheers!
You have 2 options.
Use Expression Trees to dynamically create your lambda expression
Use Dynamic LINQ as detailed on Scott Gu's blog
I've looked at both options and have successfully implemented Expression Trees as my preferred approach.
Here's an example function that i created: (NOT TESTED)
private static bool ValueExists<T>(String Value) where T : class
{
ParameterExpression pe = Expression.Parameter(typeof(T), "p");
Expression value = Expression.Equal(Expression.Property(pe, "ColumnName"), Expression.Constant(Value));
Expression<Func<T, bool>> predicate = Expression.Lambda<Func<T, bool>>(value, pe);
return MyDataContext.GetTable<T>().Where(predicate).Count() > 0;
}
Instead of using a switch statement, you can use a lookup dictionary. This is psuedocode-ish, but this is one way to get your table in question. You'll have to manually maintain the dictionary, but it should be much easier than a switch.
It looks like the DataContext.GetTable() method could be the answer to your problem. You can get a table if you know the type of the linq entity that you want to operate upon.
Dictionary<string, Type> lookupDict = new Dictionary<string, Type>
{
"Colour", typeof(MatchingLinqEntity)
...
}
Type entityType = lookupDict[AttributeFromRouteValue];
YourDataContext db = new YourDataContext();
var entityTable = db.GetTable(entityType);
var entity = entityTable.Single(x => x.Id == IdFromRouteValue);
// or whatever operations you need
db.SubmitChanges()
The Suteki Shop project has some very slick work in it. You could look into their implementation of IRepository<T> and IRepositoryResolver for a generic repository pattern. This really works well with an IoC container, but you could create them manually with reflection if the performance is acceptable. I'd use this route if you have or can add an IoC container to the project. You need to make sure your IoC container supports open generics if you go this route, but I'm pretty sure all the major players do.