Cannot use value 0 of an enumeration while defining instances of an entity - codefluent

While using CF Entities, I'm facing an issue defining instances of an entity that uses an enumeration value.
I can add the instances of the entitytwor, but during build or save an error would show up arguing:
CF0134: Instance value for key property 'EnumType' of entity 'Namespace.Entity' cannot be equal to the key property default value '0' of type 'System.Int32' ...
XML would present associated enumeration value for the property as expected.
It looks like the problem only occurs when first enumeration value is being used (associated value 0). Other lines won't be a problem.
Is there any particular things to do while defining enumeration values or use of them ?
Thanks for your answer

CodeFluent Entities defines the concept of "default value" for properties of any type, including value types and enums. The default value allows to store null in a database without having to use .NET Nullable type.
<cf:enumeration name="EmailStatus">
<cf:enumerationValue name="Valid" /> <!-- will become NULL in the Database -->
<cf:enumerationValue name="Invalid" />
</cf:enumeration>
Although the default values behavior is enabled by default you can also change it:
at the Property level by setting its usePersistenceDefaultValue attribute to false:
<cf:property typeName="EmailStatus" usePersistenceDefaultValue="false" />
at the Enumeration level by setting its usePersistenceDefaultValue attribute to false:
<cf:enumeration usePersistenceDefaultValue="false" />
at the Project level by setting its defaultUsePersistenceDefaultValue attribute to false:
<cf:project defaultUsePersistenceDefaultValue="false" />
http://blog.codefluententities.com/2012/11/15/property-default-values-and-enumerations/

Related

"FormatException in property ... " error despite valid Expression Binding syntax

I would like to display a sap.m.Button in case the value of two model properties are equal. It that possible via expression binding.
Bindings:
{user-management>/alias}
value: "TESTUSER"
{recipe-service>Author/alias}
value: "TESTUSER"
My attempts:
<Button xmlns="sap.m" visible="{= ${user-management>/alias} === ${recipe-service>Author/alias}}" />
<!-- or: -->
<Button xmlns="sap.m" visible="{= ${user-management>/alias} === ${recipe-service>Author/alias} ? true : false}"/>
The above attempts are not working resulting with the following console error:
FormatException in property 'visible' of 'Element sap.m.Button#__button1': TESTUSER is not a valid boolean value
Hint: single properties referenced in composite bindings and within binding expressions are automatically converted into the type of the bound control property, unless a different 'targetType' is specified. targetType:'any' may avoid the conversion and lead to the expected behavior.
I am not aware of using targetType for expression binding.
You must be using an OData V4 service. In that case, replace $ with % within the expression binding where the V4 OData model value is embedded but causes the above error.
Assuming the latter "recipe-service" model is sap.ui.model.odata.v4.ODataModel:
<Button xmlns="sap.m" visible="{= ${user-management>/alias} === %{recipe-service>Author/alias}}" />
See also the information about the automatic type determination in topics Changes Compared to OData V2 Model and Type Determination.

phing loadfile to property does not override previous value

<loadfile property="test-from-file" file="value.txt" />
<echo message="test-from-file = ${test-from-file}" />
<loadfile property="test-from-file" file="value2.txt" />
<echo message="test-from-file = ${test-from-file}" />
The second loadfile does not change the value of the test-from-file property.
Is there any way to get this working?
As stated in comments by Jawi, properties are not overridden by design. A property works as a constant in Phing. So if it is already defined, then it won't be changed by later property definitions.
I think that you should revert your <property> task call in order to define your preferred sources first.
Alternatively, you can also use <property override="true"> to alter default behavior and override existing values, changing properties from constant to variable.

SAPUI5 Smart Table - Smart Field make field mandatory with annotation

Is it possible to make a Property in SAPUI5 Smart Table mandatory so that a user can't leave a field empty while editing it?
I have found this document saying that it should be possible to set mandatory field control on Property in metadata.xml file with annotation like this:
<Property Name="NameLast" Type="Edm.String" Nullable="false" MaxLength="40" sap:label="Last name" sap:field-control="7" />
But with this setting I am getting following error in console:
2017-04-14 11:37:36.691429 MockServer: Resource not found for the segment '7'
2017-04-14 11:37:36.707985 The following problem occurred: HTTP request failed404,Not Found,{"error":{"code":404,"message":{"lang":"en","value":"Resource not found for the segment '7'"}}} -
EDIT:
Later I found out that sap:field-control should not contain number, but a path expression to another property which contains the number. However this also doesn't work:
<Property Name="NameLast" Type="Edm.String" Nullable="false" MaxLength="40" sap:label="Last name" sap:field-control="Name_fc" />
<Property Name="Name_fc" Type="Edm.Byte" />
Value of Name_fc property is '7'. I don't see any console error now, however I can still leave the input (NameLast) field empty without any validation and send it to OData service, which is not what I expect.
Here is a link to an example from sap where they use required fields. I have no idea though how they made it.
https://sapui5.netweaver.ondemand.com/sdk/explored.html#/sample/sap.ui.comp.sample.smartfield/code/SmartField.view.xml
For OData v2 the sap:field-control annotation on the Property can be
used to specify whether the field is mandatory.
<Property Name="Customer" ... sap:field-control="mandatory"/>
<Property Name="CompanyCode" ... sap:field-control="mandatory"/>
https://sapui5.hana.ondemand.com/#docs/api/symbols/sap.ui.comp.smartfield.SmartField.html
The mandatory property of the entity has to be nullable="false". That's it.
Have a look at the smart field example from your link:
<Property Name="Name" Type="Edm.String" Nullable="false"
MaxLength="30" sap:label="Name" sap:creatable="false"
sap:quickinfo="Property annotation DataFieldWithUrl"
sap:updatable="true" sap:sortable="false" />
Btw. thanks for sharing your smart table example!
From my understanding there are 2 options:
1) Define a specific property as Mandatory --> Nullable="false"
2) Link a property to another property in the entity, the "field-control".
This field control can contain numbers and "7" means mandatory.
The linking from option 2 can be done in the MPC_EXT class (redefine the define method).
The actual value in the "field-control" property is set in the get_entity / get_en
However I am also having an issue with the smarttable. The mandatory fields do not light up red when empty.
Do it in brute force way in the Object Page extension controller.
var oField = this.getView().byId(<FieldId>)
oField.getDataProperty().property.nullable = "false" or "true".
"false" and "true" must be a string.
To convert a boolean to string use <boolean>.toString();

CodeFluent tries to update a non-nullable foreign key of type bigint with NULL when deleting related entity

In my model I'm using bigint (ulong) as the type for entity keys.
The value 0 must be used for empty keys.
Columns for foreign keys must not be nullable, because in my methods I only want to check for the value 0 and not for null.
Everything works fine, except for the deletion of related entities that are referenced by other entities.
Here is my model:
<cf:entity name="Customer" cfom:bindingList="false">
<!--persistenceIdentity is true, because the corresponding column for this property must be auto incremented by the database.-->
<cf:property name="Id" typeName="ulong" key="true" persistenceIdentity="true" cfps:hint="CLUSTERED" />
<cf:property name="Name" typeName="string" />
</cf:entity>
<cf:entity name="Order" cfom:bindingList="false">
<!--persistenceIdentity is true, because the corresponding column for this property must be auto incremented by the database.-->
<cf:property name="Id" typeName="ulong" key="true" persistenceIdentity="true" cfps:hint="CLUSTERED" />
<!--persistenceNullable is false, because the column for the foreign key must not be nullable.-->
<cf:property name="Customer" typeName="{0}.Customer" persistenceNullable="false" />
</cf:entity>
Here is my code:
Customer customer = new Customer();
customer.Save();
Order order = new Order();
order.Customer = customer;
order.Save();
customer.Delete();
The last statement gives the following error:
Cannot insert the value NULL into column 'Order_Customer_Id', table 'CodeFluentTest.dbo.Order'; column does not allow nulls. UPDATE fails.
This is because the Customer_Delete stored procedure contains the following update statement:
UPDATE [Order] SET [Order].[Order_Customer_Id] = NULL
WHERE ([Order].[Order_Customer_Id] = #Customer_Id)
Of course this will not work, because the Order_Customer_Id column is not nullable.
How can I instruct CodeFluent to put the value 0 instead of NULL into the Order_Customer_Id column?
CodeFluent does not really support object keys that are not nullable, because the implied semantics would be somehow strange. When you delete an object, from an OO perspective, the object is now null, it's identifier does not exist any more, it's not set to a specific 0 or other value. You will probably run into other problems with tweaking the model like this.
That being said, one way to change this behavior is to use the "persistenceUnlink" attribute on the property involved, directly in the XML file. Unfortunately the graphical modeler does not support this (ancient) attribute and will override it everytime you modify the model and save it back using the GUI.
So, what you can do is use a custom aspect to automatically apply this attribute on properties where you want it. Here is a sample code for such an aspect (note the aspect runs on startup because it's really based on XML, not on the in-memory model contrary to most aspects):
<cf:project xmlns:cf="http://www.softfluent.com/codefluent/2005/1" defaultNamespace="unlink">
<cf:pattern name="Unlink Aspect" namespaceUri="http://www.example.com/unlink" preferredPrefix="ul" step="Start">
<cf:message class="_doc">
Sample aspect that removes auto unlink in delete procedures
</cf:message>
<cf:descriptor name="unlink" targets="Property" defaultValue="true" displayName="Unlink" typeName="boolean" description="Determines if this property will be unlinked during delete" category="Unlink Aspect" />
</cf:pattern>
<?code #namespace name="System" ?>
<?code #namespace name="System.Xml" ?>
<?code #namespace name="CodeFluent.Model" ?>
<?code
// use a special utility method to get all elements
// with the given attribute in a given namespace URI
var properties = Project.Package.RootModelPart.SelectElements("unlink", "http://www.example.com/unlink", false);
foreach(var property in properties)
{
// here we set a special attribute not supported by the GUI designer in Visual Studio
property.SetAttribute("persistenceUnlink", "false");
}
?>
</cf:project>
What you must do is:
save this code as a file, for example "unlink.xml" somewhere around your project files.
in the graphical modeler, right-click on the "Aspects" node of the CodeFluent project, and choose "Add existing aspect", browse to your unlink.xml file (it should display the aspect metadata), and press ok.
go back to the design surface in the graphical modeler, click on the property you want to remove persistence link, go to the Visual Studio property grid, choose the blue "aspects and producers properties" tab, and set "Unlink" to False that should now be displayed (default is true).
rebuild, and the stored procedure code should not contain links for this relation any more.

use _trackXXX columns in the business object model

Is there any way to view the persistence tracking fields (_trackLastWriteTime) as properties in my BOM.
I've seen a similar question in your website forums, but due to the updates you made to it, answers are lacking of "code" sections, so they are useless.
Thanks again!
Josep.
You can just declare the following properties to the entity:
<cf:property name="LastWriteTime" typeName="datetime" persistenceName="_trackLastWriteTime" readOnLoad="true" readOnSave="true" persistent="false"/>
<cf:property name="CreationTime" typeName="datetime" persistenceName="_trackCreationTime" readOnLoad="true" persistent="false" />
<cf:property name="CreationUser" persistenceName="_trackCreationUser" readOnLoad="true" persistent="false" />
<cf:property name="LastWriteUser" persistenceName="_trackLastWriteUser" readOnLoad="true" readOnSave="true" persistent="false" />
persistenceName should match the column name. This is the default column name but it could be different in your context. The property name is not important, only the persistence/column name.
persistent = false means the property is not persistent. This instructs the inference pipeline to not create a column corresponding to this property (because in fact it has already created that column).
readOnLoad = true and/or readOnSave = true means all layers will load and/or save this property, although it's been marked as non persistent.