How to manually instantiate ActiveRecord truncated objects? - sql

Working with ActiveRecord and JRuby, I try to invoke a stored procedure on a Database. Using the underlying Java Library I reached a point where I have a hash with the columns specified in the select.
Now I'd like to use this hash to have ActiveRecord models, but I'd like them to look like if I did a classic Model.select(columns).all (with only the columns values, errors when trying to reach the other ones and readonly).
There must be something inside of AR to do this but I can't find anything and all my search leads to all the basic "fetch" tutorials ...

OK so I kept digging in Rails code and figured out my answer was the instantiate method.
The idea is if you are inside a model called MyModel and do this
object = instantiate(value1: 1, value2: 'ok')
you will have an instance of the MyModel class with theses attributes defined. If the model is supposed to have more columns, they are not defined. The object is readonly.

Related

How to call remove_column on SALV table?

I want to execute the method remove_column on an instance of cl_salv_column_table but because of its visibility level, I am not able to do so.
Plan:
I already tried inheriting from cl_salv_columns_list and then perform the call inside the remove-method:
CLASS lcl_columns_list DEFINITION INHERITING FROM CL_SALV_COLUMNS_LIST.
PUBLIC SECTION.
METHODS:
remove IMPORTING iw_colname TYPE string.
ENDCLASS.
But apparently my casting knowledge got rusty as I'm not able to figure out an appropriate solution.
This is my current hierarchy - the red arrows show the way I would have to take:
My approach looks like this:
DATA lo_column_list TYPE REF TO lcl_columns_list.
lo_column_list ?= CAST cl_salv_columns_list( lo_columns ).
But it fails with:
CX_SY_MOVE_CAST_ERROR
Source type: \CLASS=CL_SALV_COLUMNS_TABLE
Target type: "\PROGRAM=XXX\CLASS=LCL_COLUMNS_LIST"
Background:
My task is to select all columns of 3 tables (which would be done like SELECT t1~*, t2~*, t3~* ...) as long as their names don't conflict (e.g. field MANDT should only be displayed once). This would require defining a very big structure and kick the size of the selection list to a maximum.
To avoid this, I wanted to make use of the type generated by my inline-declaration. Hiding the individual columns via set_visible( abap_false ) would still display them in the layout manager - which looks really ugly.
Is there any other way to accomplish my target?
Use set_technical( abap_true ) to hide the columns entirely. As for your approach - sorry, inheritance does not work that way - in no statically typed object oriented language that I know. You can't 'recast' an instantiated object to a different class. You would need to modify the framework extensively to support that.

Using the DoctrineObjectConstructor, how are new entities created?

I am attempting to use JMSSerializerBundle to consume JSON into Doctrine entities. I need to both create new entities where they do not already exist in the database, and update existing entities when they do already exist. I am using the DoctrineObjectConstructor included in the JMSSerializer package to help with this. When I consume JSON which contains a property designated as an identifier, such as:
{
"id": 1,
"some_other_attribute": "stuff"
}
by attempting to deserialize it, JMSSerializer causes warnings and eventually dies with an exception for attempting to utilize reflection to set properties on a null value. The warnings all look like this:
PHP Warning: ReflectionProperty::setValue() expects parameter 1 to be object, null given in /Users/cdonadeo/Repos/Ubertester/vendor/jms/serializer/src/JMS/Serializer/GenericDeserializationVisitor.php on line 176
If I manually insert an entity with ID 1 in my database and make another attempt then I receive no errors and everything appears to be working correctly, but I'm now short half my functionality. I looked at the code for the DoctrineObjectConstructor class, and at the top is a comment:
/**
* Doctrine object constructor for new (or existing) objects during deserialization.
*/
But I don't see how it could possibly create a new a new entity because after the construct() function has done all of its checks, at the end it calls:
$object = $objectManager->find($metadata->name, $identifierList);
And since the identifier does not exist in the database the result is null which is ultimately what gets returned from the function. This explains why inserting a row in the database with the appropriate ID makes things work: find() now returns a proper Entity object, which is what the rest of the library expects.
Am I using the library wrong or is it broken? I forked the Git repo and made an edit, and trying it out everything seems to work more or less the way I expected. That edit does have some drawbacks that make me wonder if I'm not just making this more difficult than it has to be. The biggest issue I see is that it will cause persisted and unpersisted entities to be mixed together with no way to tell which ones are which, but I don't know if that's even a big deal.
For Doctrine entities use configuration:
jms_serializer:
object_constructors:
doctrine:
fallback_strategy: "fallback" # possible values ("null" | "exception" | "fallback")
see configuration reference https://jmsyst.com/bundles/JMSSerializerBundle/master/configuration

Yii CActiveRecord with Column Named "attributes"

I used the CRUD generator from a legacy database. When searching for a column value I get the following error:
htmlspecialchars() expects parameter 1 to be string, array given (/usr/local/share/yii/framework/web/helpers/CHtml.php:103)
The problem is that the model has an existing column named "attributes" which is creating a conflict. I removed the entry from the _search.php and commented out all instances in the model hoping to at least get it working but no luck. Any suggestions would be appreciated.
Thanks.
Every CActiveRecord instance (or CModel instance for that matter) has a getter/setter named attributes with which all the attributes can be set. This leads to a conflict because the generated crud code uses the attributes attribute expecting it works as described before.
The controller does something like:
$model->attributes=$_POST['ModelClassName'];
// or
$model->attributes=$_GET['ModelClassName'];
This is meant to set al the (safe) attributes of the model at once. Instead this overwrites the database attribute attributes of your legacy DB model.
This in turn leads to the error you describe, because $_GET['ModelClassName'] and $_POST['ModelClassName'] typically contain arrays of data.
I guess the easiest fix would be to directly call the setter function for the "normal" attributes behavior which would lead to replacing the lines mentioned above with something like the following:
// in the controller
$model->setAttributes($_POST['ModelClassName']);
// and
$model->setAttributes($_GET['ModelClassName']);
I think rest of the generated CRUD code (the views) could and should be left untouched to make it work.
If you want to know how and why this works, it's best to do some research into the __get and __set magic functions and how they're used in the yii framework.

CF9 ORM Populating an entity with an object

I am using Model-Glue/Coldspring for a new application and I thought I would throw CF9 ORM into the mix.
The only issue I am having right now is with populating an entity with an object. More or less the code below verifies that only one username can exist. There is some other logic that is not displayed.
My first thought was to using something like this:
var entity = entityload('UserAccount' ,{UserName=arguments.UserAccount.getUserName()},"true")
entity = arguments.UserAccount;
How ever this does not work the way that I expected. Is it even possible to populate an entity with an object or do I need to use the setters?
Not sure if this is what you're looking for. If you have...
component persistent="true" entityName="Foo"
{
property a;
property b;
}
You can pass a struct in the 2nd param to init the entity (added in CF9.0.1 I believe)
EntityNew("Foo", {a="1",b="2"});
To populate Foo with another object, you can use the Memento pattern, and implement a GetMemento() function to your object that returns a struct of all its properties.
EntityNew("Foo", bar.getMemento());
However, CF does NOT call your custom setters! If you want to set them using setters, you may add calls to the setters in your init() constructor, or use your MVC framework of choice to populate the bean. In Model-Glue, it is makeEventBean().
Update: Or... Here's hack...
EntityNew("Foo", DeserializeJSON(SerializeJSON(valueObject)));
Use this at your own risk. JSON might do weird things to your numbers and the 'yes','no','true','false' strings. :)
Is it even possible to populate an entity with an object or do I need to use the setters?
If you mean "Is it possible to create load an ORM Entity from an instance of that persistent CFC that already exists and has properties set?", then yes you can using EntityLoadByExample( object,[unique] )
entity = EntityLoadByExample( arguments.userAccount,true );
This assumes the userAccount CFC has been defined as persistent, and its username value has been set before being passed in (which seems to be the case in your situation).
Bear in mind that if any other properties have been set in the object you are passing, including empty strings, they will be used as filters to load the entity, so if they do not exactly match a record in your database, nothing will be loaded.

serialized object not being converted

I have a Model called statistics which has a value field that contains Goals (a self defined class) data
class Statistic < ActiveRecord::Base
serialize :value
end
When I try to access the goals_against (an atr_reader of the Goals class) I get
undefined method `goals_against' for #<String:0x54f8400>
The value property contains following data:
--- !ruby/object:Goals \ngoals: {}\n\ngoals_against: 1\ngoals_for: 0\nversion: 1\n
In string format according to the debugger.
It seems that rails doesn't know this data is of type Goals.
Someone knows how to solve this?
Thanks
Three things:
First, where ever your Goal class is defined, make sure it is loaded. At some point Rails stopped auto-loading stuff in the lib folder. So where ever your extra classes are located, set them in config.autoload_paths (in config/application.rb).
Second, when you declare a column as serialized, you have the option of specifying the class. This is especially useful when you are working with a custom class and you want to make sure Rails does the conversion correctly.
serialize :value, Goal
Third, when you have a column that is serialized, make sure you have enough room for it. In other words, most of the time you're going to want that column to be "text" and not "string" in your schema (otherwise your sql engine will silently truncate anything too large to fit in a string column and you'll end up saving a broken object).