Serializing PropertyBusinessObject to XML - codenameone

I'm trying to upgrade the code quality of a part of my app which can display data within dynamic Form that are configured via an XML string translated into an object. Until now, I was doing parsing and serializing with custom methods only, nearly writing each line of XML myself. That's obviously the wrong approach and I fully understand it now that I'm very familiar with Codename One.
So I rewrote my objects to use the PropertyBusinessObject interface and here are the resulting classes :
public class CForm implements PropertyBusinessObject
{
Property<String, CForm> type = new Property<>("type");
Property<String, CForm> label = new Property<>("label");
IntProperty<CForm> currentStep = new IntProperty<>("currentstep");
IntProperty<CForm> maxsteps = new IntProperty<>("maxsteps");
ListProperty<CFormField, CForm> fields = new ListProperty<>("fields", CFormField.class);
ListProperty<CFormStep, CForm> steps = new ListProperty<>("steps", CFormStep.class);
public CForm()
{
}
PropertyIndex index;
#Override
public PropertyIndex getPropertyIndex()
{
if(index == null)
index = new PropertyIndex(this, "CForm",
new PropertyBase[] {type, label, currentStep, maxsteps, fields, steps});
return index;
}
}
This class is the main one, describing the general structure of the process. Type and label are used internally to identify the model used and the job to do at the customer place. Fields are the dynamic fields that will be shown at each step, these are global fields, like remarks or so. The steps are the differents dynamic Forms that will be shown to the user. maxSteps and currentStep are used to know where the user is in the process.
public class CFormStep implements PropertyBusinessObject
{
Property<String, CFormStep> name = new Property<String, CFormStep>("name");
Property<String, CFormStep> label = new Property<String, CFormStep>("label");
IntProperty<CFormStep> value = new IntProperty<CFormStep>("value");
ListProperty<CFormField, CFormStep> fields = new ListProperty<>("fields", CFormField.class);
public CFormStep() {}
PropertyIndex index;
#Override
public PropertyIndex getPropertyIndex()
{
if(index == null)
index = new PropertyIndex(this, "CFormStep",
new PropertyBase[] { label, name, value, fields});
return index;
}
}
Each step is described with an unique name, a label used as the title of the dynamic form and a value to order the steps within the CForm. Like it's CForm parent, it has a set of fields.
public class CFormField implements PropertyBusinessObject
{
Property<String, CFormField> label = new Property<String, CFormField>("label");
Property<String, CFormField> name = new Property<String, CFormField>("name");
Property<String, CFormField> type = new Property<String, CFormField>("type");
Property<String, CFormField> value = new Property<String, CFormField>("value");
Property<String, CFormField> parent = new Property<String, CFormField>("parent");
public CFormField() {}
PropertyIndex index;
#Override
public PropertyIndex getPropertyIndex()
{
if(index == null)
index = new PropertyIndex(this, "CFormField",
new Property[] { label, name, type, value, parent });
return index;
}
}
The fields are composed of a label, an unique name, a type used to define which component will be used to render it, the value selected by the user formatted as a String and finally it's optionnal parent name.
The old implementation was fonctionnal but laggy and hard to evolve, which is why I came to write this new one.
But I'm stuck with one problem : I already rewroted the PropertyIndex.fromXML(Element e) since it was creating NPE's when calling
public void fromXml(Element e) {
Hashtable atts = e.getAttributes();
for(Object a : atts.keySet()) { <--- NPE there if no attributes
and was not supporting ListProperties.
Reading my CForm from XML works fine but when I try to serialize it back to XML I just got a <CForm><CForm/> and don't fully understand how the PropertyXMLElement works... I've already debugged the process and the PropertyBusinessObject is not empty at all. Any idea on how to fill the XML with those values ?
Here is an example of XML used :
<CForm>
<type>delivery-install</type>
<label>Intervention Test</label>
<currentstep/>
<maxsteps>3</maxsteps>
<fields>
<CFormField>
<label>Remarques</label>
<name>globalTEXTAREA6</name>
<type>TEXTAREA</type>
<value/>
</CFormField>
</fields>
<steps>
<CFormStep>
<name>step1</name>
<label>Arrivée sur place</label>
<value>1</value>
<fields>
<CFormField>
<label>Heure d'arrivée</label>
<name>step1TIME3</name>
<type>TIME</type>
<value/>
</CFormField>
</fields>
</CFormStep>
<CFormStep>
<name>step2</name>
<label>Sur place</label>
<value>2</value>
<fields>
<CFormField>
<label>Produits livrés / utilisés</label>
<name>step2PRODUCTTABLE7</name>
<type>PRODUCTTABLE</type>
<value/>
</CFormField>
</fields>
</CFormStep>
<CFormStep>
<name>step3</name>
<label>Départ</label>
<value>3</value>
<fields>
<CFormField>
<label>Heure de départ</label>
<name>step3TIME4</name>
<type>TIME</type>
<value/>
</CFormField>
<CFormField>
<label>Signature client</label>
<name>step3SIGN5</name>
<type>SIGN</type>
<value/>
</CFormField>
</fields>
</CFormStep>
</steps>
</CForm>

The XML support in property business object is still a work in progress which is why I didn't blog about it. I fixed the NPE issue and added support for list properties to fix the two issues raised. Notice I only did this for reading so there might be issues writing these objects as we didn't have time to do QA on this feature.

Related

map key value pair with entity properties in entity framework

Below is my code for entity and a function where I need to map entity TblEmployee from a key value pair.
In foreach loop I am getting values based on keys, what should be the best approach to do it?
public class TblEmployee
{
public int EmployeeId { get; set; }
public string Name { get; set; }
}
public int Create()
{
tblEmployee employee = new tblEmployee();
using (var ctx = new theparkeee_testEntities())
{
foreach (string key in HttpContext.Current.Request.Form.AllKeys)
{
string value = HttpContext.Current.Request.Form[key];
//how to map value from key value pair to entity employee.
}
}
}
You can use System.Reflection to get the Properties of an object by their name with Type.GetProperty(string name). After you got the PropertyInfo, you can use SetValue to assign a value to it.
foreach (string key in HttpContext.Current.Request.Form.AllKeys) {
// note that "value" is a reserved word, do not use it as variable name
string val = HttpContext.Current.Request.Form[key];
var propertyInfo = typeof(TblEmployee).GetProperty(key); // can maybe be moved outside of the loop
if (propertyInfo != null) {
propertyInfo.SetValue(employee, val);
}
}
This will work for string properties. If the property is of another type, you have to find the correct type (again, using reflection) and cast the string value before assigning it.
Note that this is not the correct approach to store data in MVC. You should not work with the Request.Form directly, instead your POST action should accept a ViewModel that can be mapped (e.g. using Automapper) to the DB entity. I.e. let the ASP ModelBinder do its work, instead of reinventing the wheel!
[HttpPost]
public ActionResult Submit(MyViewModel postData) {
var employee = Mapper.Map<TblEmployee>(postData);
_ctx.Employees.Add(employee);
_ctx.SaveChanges();
return new HttpStatusCodeResult((int)HttpStatusCode.OK);
}

Populating a table from a file only last column is populated JavaFX [duplicate]

This has baffled me for a while now and I cannot seem to get the grasp of it. I'm using Cell Value Factory to populate a simple one column table and it does not populate in the table.
It does and I click the rows that are populated but I do not see any values in them- in this case String values. [I just edited this to make it clearer]
I have a different project under which it works under the same kind of data model. What am I doing wrong?
Here's the code. The commented code at the end seems to work though. I've checked to see if the usual mistakes- creating a new column instance or a new tableview instance, are there. Nothing. Please help!
//Simple Data Model
Stock.java
public class Stock {
private SimpleStringProperty stockTicker;
public Stock(String stockTicker) {
this.stockTicker = new SimpleStringProperty(stockTicker);
}
public String getstockTicker() {
return stockTicker.get();
}
public void setstockTicker(String stockticker) {
stockTicker.set(stockticker);
}
}
//Controller class
MainGuiController.java
private ObservableList<Stock> data;
#FXML
private TableView<Stock> stockTableView;// = new TableView<>(data);
#FXML
private TableColumn<Stock, String> tickerCol;
private void setTickersToCol() {
try {
Statement stmt = conn.createStatement();//conn is defined and works
ResultSet rsltset = stmt.executeQuery("SELECT ticker FROM tickerlist order by ticker");
data = FXCollections.observableArrayList();
Stock stockInstance;
while (rsltset.next()) {
stockInstance = new Stock(rsltset.getString(1).toUpperCase());
data.add(stockInstance);
}
} catch (SQLException ex) {
Logger.getLogger(WriteToFile.class.getName()).log(Level.SEVERE, null, ex);
System.out.println("Connection Failed! Check output console");
}
tickerCol.setCellValueFactory(new PropertyValueFactory<Stock,String>("stockTicker"));
stockTableView.setItems(data);
}
/*THIS, ON THE OTHER HAND, WORKS*/
/*Callback<CellDataFeatures<Stock, String>, ObservableValue<String>> cellDataFeat =
new Callback<CellDataFeatures<Stock, String>, ObservableValue<String>>() {
#Override
public ObservableValue<String> call(CellDataFeatures<Stock, String> p) {
return new SimpleStringProperty(p.getValue().getstockTicker());
}
};*/
Suggested solution (use a Lambda, not a PropertyValueFactory)
Instead of:
aColumn.setCellValueFactory(new PropertyValueFactory<Appointment,LocalDate>("date"));
Write:
aColumn.setCellValueFactory(cellData -> cellData.getValue().dateProperty());
For more information, see this answer:
Java: setCellValuefactory; Lambda vs. PropertyValueFactory; advantages/disadvantages
Solution using PropertyValueFactory
The lambda solution outlined above is preferred, but if you wish to use PropertyValueFactory, this alternate solution provides information on that.
How to Fix It
The case of your getter and setter methods are wrong.
getstockTicker should be getStockTicker
setstockTicker should be setStockTicker
Some Background Information
Your PropertyValueFactory remains the same with:
new PropertyValueFactory<Stock,String>("stockTicker")
The naming convention will seem more obvious when you also add a property accessor to your Stock class:
public class Stock {
private SimpleStringProperty stockTicker;
public Stock(String stockTicker) {
this.stockTicker = new SimpleStringProperty(stockTicker);
}
public String getStockTicker() {
return stockTicker.get();
}
public void setStockTicker(String stockticker) {
stockTicker.set(stockticker);
}
public StringProperty stockTickerProperty() {
return stockTicker;
}
}
The PropertyValueFactory uses reflection to find the relevant accessors (these should be public). First, it will try to use the stockTickerProperty accessor and, if that is not present fall back to getters and setters. Providing a property accessor is recommended as then you will automatically enable your table to observe the property in the underlying model, dynamically updating its data as the underlying model changes.
put the Getter and Setter method in you data class for all the elements.

How to search for empty strings in a text field with Entity Framework?

I'd like to know how can I search for empty strings when I'm using a text type field with Entity Framework.
I've looked the SQL query that Entity is generating and It's using LIKE to compare because It's searching in a text type field, so when I use .Equals(""), == "", == string.Empty, .Contains(""), .Contains(string.Empty), and everything else, It's returning all results because it sql query is like '' and the == command throws exception because It uses the = command that is not valid with text type field.
When I try to use .Equals(null), .Contains(null), == null, It returns nothing, because It is generating FIELD ISNULL command.
I already tried the .Lenght == 0 but It throws an exception...
This works for me:
public class POCO
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
static void Main(string[] args)
{
var pocos = new List<POCO>
{
new POCO { Id = 1, Name = "John", Description = "basic" },
new POCO { Id = 2, Name = "Jane", Description = "" },
new POCO { Id = 3, Name = "Joey", Description = string.Empty }
};
pocos.Where(x => x.Description == string.Empty)
.ToList()
.ForEach(x => Console.WriteLine($"{x.Id} {x.Name} {x.Description}"));
}
However the issue MAY BE that your T4 generated object is not fully realized with data you can use, if you are using Entity Framework. EG the translation from the database is not populating objects to interrogate correctly. I would just do an operation like this to see:
using (var context = new YOURCONTEXTNAME())
{
var persons = context.YOURDATABASEOBJECT.ToList();
persons.ForEach(x => Console.WriteLine($"{x.COLUMNINQUESTION}"));
}
If you are successfully having data in it, it should be retrieved. I would not use text if possible. Use a varchar(max) nvarchar(max) xml, whatever text will be deprecated eventually and is bad form so to speak to continue using at this point.
EDIT
Okay I see, the answer is you cannot interogate the object until it is fully realized when it is text. I did a test on my local database and created a context and tested it and sure enough you cannot do a '== string.empty', '== ""', or 'String.IsNullOrEmpty()' on a text. However you can do it once the object is materialized in a realized object. EG:
// Won't work as context does not understand type
//var persons = context.tePersons.Where(x => x.Description == string.Empty).ToList();
//Works fine as transformation got the object translated to a string in .NET
var start = context.tePersons.ToList();
var persons = start.Where(x => x.Description == String.Empty).ToList();
This poses a problem obviously as you need to get ALL your data potentially before performing a predicate. Not the best means by any measure. You could do a sql object for this instead then to do a function, proc, or view to change this.

Entity Framework : Create a model from Dictionary<TKey,TValue> to be mapped to a database table

Earlier I had a table named ApplicationConfiguration which simply had [Key],[Value] columns to store some config data. This was queried straight away using SQL queries.
Now I intend to make use of Entity Framework (EF) Code First approach to query this table. The specialty of this table is that the table will have only a fixed number of rows in its lifetime. Only the Value column can be updated.
So as per the code first approach, we have to first write our POCO classes with its properties that will be mapped to columns in the underlying table. However, I wish to have a Dictionary<> structure to represent these configuration KV pairs. My concern is, will EF be able to fire update queries against any updation to the the value of a particular pair.
Also since I am using Code First approach, I would want some seed data(i.e the fixed number of rows and its initial content) to the added after the table itself is created on the fly when the application is first executed.
If Dictionary<> cannot be used, please suggest some alternative. Thanks in advance.
Coded this way:
public class ApplicationConfiguration
{
public int Id { get; set; }
public string Key { get; set; }
public int Value { get; set; } // should be string, but I'm lazy
}
class Context : DbContext
{
internal class ContextInitializer : DropCreateDatabaseIfModelChanges<Context>
{
protected override void Seed(Context context)
{
var defaults = new List<ApplicationConfiguration>
{
new ApplicationConfiguration {Key = "Top", Value = 5},
new ApplicationConfiguration {Key = "Bottom", Value = 7},
new ApplicationConfiguration {Key = "Left", Value = 1},
new ApplicationConfiguration {Key = "Right", Value = 3}
};
// foreach (var c in defaults)
// context.ConfigurationMap.Add(c.Key, c); // by design, no IReadOnlyDictionary.Add
foreach (var c in defaults)
context.ApplicationConfigurations.Add(c);
base.Seed(context);
}
}
public Context()
{
Database.SetInitializer(new ContextInitializer());
}
private IDbSet<ApplicationConfiguration> ApplicationConfigurations
{
get { return Set<ApplicationConfiguration>(); }
}
public IReadOnlyDictionary<string, ApplicationConfiguration> ConfigurationMap
{
get { return ApplicationConfigurations.ToDictionary(kvp => kvp.Key, kvp => kvp); }
}
}
Used this way:
using (var context = new Context())
{
ReadConfigurationOnly(context.ConfigurationMap);
}
using (var context = new Context())
{
ModifyConfiguration(context.ConfigurationMap);
context.SaveChanges();
}
static void ReadConfigurationOnly(IReadOnlyDictionary<string, ApplicationConfiguration> configuration)
{
foreach (var k in configuration.Keys)
Console.WriteLine("{0} = {1}", k, configuration[k].Value);
}
static void ModifyConfiguration(IReadOnlyDictionary<string, ApplicationConfiguration> configuration)
{
foreach (var k in configuration.Keys)
configuration[k].Value++; // this is why I was lazy, using an int for a string
}
So, I wrote it up this way — using an int Value property rather than a string — just so I could run the "Used this way" code over and over, and see the database update each time, without having to come up with some other way to change Value in an interesting way.
It's not quite as nifty here to use a IReadOnlyDictionary<string, ApplicatonConfiguration> instead of a IReadOnlyDictionary<string, string>, the way we'd really like, but that's more than made up for by the fact that we can easily modify our collection values without resorting to a clumsier Set method taking a dictionary as input. The drawback, of course, is that we have to settle for configuration[key].Value = "new value" rather than configuration[key] = "new value", but — as I say — I think it's worth it.
EDIT
Dang! I wrote this code up specifically to answer this question, but I think I like it so much, I'm going to add it to my bag of tricks ... this would fit in really well when my company goes from local databases to Azure instances in the cloud, and the current app.config has to go into the database.
Now all I need is a ContextInitializer taking a System.Configuration.ConfigurationManager as a ctor parameter in order to seed a new database from an existing app.config ...
I don't think you can map a table directly to a Dictionary; you will probably have to write your own wrapper to fill a dictionary from the table and update it back to the DB. Entities are each a row of a given table... Something like this (untested):
public Dictionary<string, string> GetDictionary()
{
Dictionary<string, string> dic = new Dictionary<string, string>();
using (var db = new Context())
{
var configs = db.ApplicationConfiguration.Select();
foreach (var entry in configs)
{
dic.Add(config.Key, config.Value);
}
}
return dic;
}
public void SaveConfig(Dictionary<string, string> dic)
{
using (var db = new Context())
{
foreach (KeyValuePair kvp in dic)
{
if (!db.ApplicationConfiguration.First(a => a.Key == kvp.Key).Value == kvp.Value)
{
var ac = new ApplicationConfiguration();
ac.Key = kvp.Key;
ac.Value = kvp.Value;
db.Entry(ac).State = EntityState.Modified;
}
}
db.SaveChanges();
}
}
For your second question, you want to use the Seed() method to add initial values to the database. See here for an example implementation.

GAE/JPA/DataNucleus: Strange exception while trying to persist entity (IllegalArgumentException: out of field index :-1)

I'm getting an exception after I added this embedded field in my entity:
#Entity
public class Team extends DataObject
{
#Embedded
private TeamEvolution teamEvolution = new TeamEvolution();
// NEW FIELD:
#Embedded
// #AttributeOverrides({ #AttributeOverride(name = "buffer", column = #Column) })
// #Enumerated
private ScoutBuffer scoutBuffer;
...
This guy is very simple:
#Embeddable
public class ScoutBuffer
{
private static final int BUFFER_SIZE = 150;
#Basic
private List<String> buffer;
... // from here on there are only methods...
When I try to merge my modifications I get the following exception:
java.lang.IllegalArgumentException: out of field index :-1
at com.olympya.futweb.datamodel.model.ScoutBuffer.jdoProvideField(ScoutBuffer.java)
at org.datanucleus.state.JDOStateManagerImpl.provideField(JDOStateManagerImpl.java:2585)
at org.datanucleus.state.JDOStateManagerImpl.provideField(JDOStateManagerImpl.java:2555)
at org.datanucleus.store.mapped.mapping.CollectionMapping.postUpdate(CollectionMapping.java:185)
at org.datanucleus.store.mapped.mapping.EmbeddedPCMapping.postUpdate(EmbeddedPCMapping.java:133)
// etc, etc...
I don't think there's anything to do, but I had to use JDOHelper.makeDirty before merging the entity for it to perceive that I modified scoutBuffer:
team.getScoutBuffer().add(playerIds);
JDOHelper.makeDirty(team, "scoutBuffer");
em.merge(team);
As you can see commented in the code, I tried the workaround described here, without success. Strange thing is that is from 2009... I'm using GAE 1.7.0, by the way. Also, I tried cleaning/re-enhancing the datamodel.

Resources