Binding data to view model when dealing with DAO and Tornadofx - data-binding

I am making database operations with JetBrains/Exposed. I was able to make use of the DAO approach to display data from the database on the TableView. It was quite challenging with the DSL approach.
After succeeding to display data, data binding was gone. My person class looks like this
class Person(id: EntityID<Int>) : IntEntity(id) {
companion object : IntEntityClass<Person>(Persons)
var name by Persons.name
var title by Persons.title
}
my view model looks like this
class PersonModel(person: Person?) : ViewModel() {
val name = bind {person?.observable(Person::name)}
val title = bind {person?.observable(Person::title)}
}
Each time I want to commit a change to the model I get
java.lang.IllegalStateException: No transaction in context.
I know this is because Person is used in the transaction context to perform Db queries.
I wish to know how I can bind data to view model given that I am using DAO API of JetBrains/Expose.
Thanks.

Related

Corda - Queries on QueryableState Child Tables

Background
I have a problem with being able to query child data in a sample Corda application, demonstrating how to persisnt hierarchical data using QueryableState.
For reference:
https://github.com/corda/samples-kotlin/tree/master/Features/queryableState-carinsurance
https://www.corda.net/blog/persisting-corda-states-in-custom-database-tables-using-queryablestate/
The car insurance sample demonstrates how to set up:
a One-to-One relationship between PersistentInsurance and PersistentVehicle
a One-to-Many relationship between PersistentInsurance and PersistentClaim
Problem
What the car insurance sample doesn't demonstrate is how to query that data. Building vault queries from PersistentInsurance is fairly trivial as we can use VaultCustomQueryCriteria to build custom query expressions over the properties of PersistentInsurance, however the same is not true for the child tables in the hierarchy. This is because PersistentInsurance extends PersistentState, whereas PersistentVehicle and PersistentClaim don't.
For Reference, the underlying type hierarchy for PersistentState is as follows:
StatePersistable > DirectStatePersistable > PersistentState
interface StatePersistable
interface DirectStatePersistable : StatePersistable {
val stateRef: PersistentStateRef?
}
class PersistentState(#EmbeddedId override var stateRef: PersistentStateRef? = null) : DirectStatePersistable
data class PersistentStateRef(
#Suppress("MagicNumber") // column width
#Column(name = "transaction_id", length = 144, nullable = false)
var txId: String,
#Column(name = "output_index", nullable = false)
var index: Int
) : Serializable {
constructor(stateRef: StateRef) : this(stateRef.txhash.toString(), stateRef.index)
}
Going back to the car insurance sample, we can't use VaultCustomQueryCriteria for PersistentVehicle or PersistentClaim as VaultCustomQueryCriteria::expression has a generic constraint on StatePersistable:
data class VaultCustomQueryCriteria<L : StatePersistable>(
val expression: CriteriaExpression<L, Boolean>,
...
) : CommonQueryCriteria() { ... }
What I've Tried
Implementing StatePersistable on PersistentVehicle and/or PersistentClaim causes the following error when you create a VaultCustomQueryCriteria using any of the properties from those classes:
net.corda.core.node.services.VaultQueryException: Parsing error: Unable to locate Attribute with the the given name [stateRef] on this ManagedType [...$PersistentClaim]
Implementing DirectStatePersistable or PersistentState on PersistentVehicle and/or PersistentClaim causes an internal error when finalizing the transaction. The flow hangs and eventually times out. I wasn't able to determine exactly where the error occurs as the code is buried inside internal implementations for underlying Corda services.
What Does Work (In a Limited Capacity)
I'm aware that we can execute custom SQL queries; for example:
val sqlQuery = buildString {
appendln("SELECT TRANSACTION_ID, OUTPUT_INDEX")
appendln("FROM CLAIM_DETAIL")
appendln("WHERE claimNumber = '123'")
}
val stateRefs = serviceHub.jdbcSession().executeCaseInsensitiveQuery(sqlQuery).map {
val txId = SecureHash.parse(it.getString("TRANSACTION_ID")
val index = it.getInt("OUTPUT_INDEX")
StateRef(txId, index)
}.toList().toBlocking().first()
VaultQueryCriteria(stateRefs = stateRefs)
Needless to say, that's hideous compared to:
VaultCustomQueryCriteria(PersistentClaim::claimNumber.equal("123"))
As for why it works in a limited capacity, this works fine for queries inside the node, which access to the service hub, but doesn't work over RPC as there's no access to a jdbcSession.
So, any ideas (if it's at all possible), on how we can improve the query capability of child tables?
#Matthew Layton I have put your concerns to the engineering team. The team has looked into this.
To address/fix this issue, requires lot of platform changes.
For time being I would suggest you to manage with using native queries. We are planning to prioritise this issue. I will keep you posted on this.

EF Core Update with List

To make updates to a record of SQL Server using Entity Framework Core, I query the record I need to update, make changes to the object and then call .SaveChanges(). This works nice and clean.
For example:
var emp = _context.Employee.FirstOrDefault(item => item.IdEmployee == Data.IdEmployee);
emp.IdPosition = Data.IdPosition;
await _context.SaveChangesAsync();
But is there a standard method if I want to update multiple records?
My first approach was using a list passing it to the controller, but then I would need to go through that list and save changes every time, never really finished this option as I regarded it as not optimal.
For now what I do is instead of passing a list to the controller, I pass each object to the controller using a for. (kind of the same...)
for(int i = 0; i < ObjectList.Count; i ++)
{
/* Some code */
var httpResponseObject = await MyRepositories.Post<Object>(url+"/Controller", Object);
}
And then do the same thing on the controller as before, when updating only one record, for each of the records...
I don't feel this is the best possible approach, but I haven't found another way, yet.
What would be the optimal way of doing this?
Your question has nothing to do with Blazor... However, I'm not sure I understand what is the issue. When you call the SaveChangesAsync method, all changes in your context are committed to the database. You don't have to pass one object at a time...You can pass a list of objects
Hope this helps...
Updating records in bulk using Entity Framework or other Object Relational Mapping (ORM) libraries is a common challenge because they will run an UPDATE command for every record. You could try using Entity Framework Plus, which is an extension to do bulk updates.
If updating multiple records with a single call is critical for you, I would recommend just writing a stored procedure and call if from your service. Entity Framework can also run direct queries and stored procedures.
It looks like the user makes some changes and then a save action needs to persist multiple records at the same time. You could trigger multiple AJAX calls—or, if you need, just one.
What I would do is create an endpoint—with an API controller and an action—that's specific to your needs. For example, to update the position of records in a table:
Controller:
/DataOrder
Action:
[HttpPut]
public async void Update([FromBody] DataChanges changes)
{
foreach(var change in changes)
{
var dbRecord = _context.Employees.Find(change.RecordId);
dbRecord.IdPosition = change.Position;
}
_context.SaveChanges();
}
public class DataChanges
{
public List<DataChange> Items {get;set;}
public DataChangesWrapper()
{
Items = new List<DataChange>();
}
}
public class DataChange
{
public int RecordId {get;set;}
public int Position {get;set;}
}
The foreach statement will execute an UPDATE for every record. If you want a single database call, however, you can write a SQL query or have a stored procedure in the database and pass the data as a DataTable parameter instead.

How to get the selected value in a dropbox generated by Data Contract?

I am trying to get the selected value of a dropdown box generated by Data Contract.
my code is something like this:
Code in Data Contract
public EDTenum parmSource(EDTenum _source = source)
{
source = _source;
return source;
}
the dropdown data are ENUM.
I am not sure but I declared the parmSource in my Data Provider like so:
EDTenum source;
contract = this.parmDataContract();
source = contract.parmSource();
So source is where the value of the dropdown box stored. (I don't know if this is correct as well)
Really just want to get the value selected in the dropdown created from the Data Contract.
Typically you call contract = this.getDataContractObject() to get your contract in a later context.
Also, do you decorate your contract and its members correctly with attributes? See here:
https://technet.microsoft.com/en-us/library/gg844225.aspx

Spring Data Neo4j 4: Bug when updating property to null?

I use Spring Data Neo4j 4 GraphRepository to save and retrieve data. Using GraphRepository save() and findAll() methods.
When I update an existing entity property to null, it seems that changes are not reflected in the returned data.
If I update the property to any other non-null value, the changes are reflected correctly.
I can see that the null property update is performed on the DB server. But the findAll() method doesn't reflect the change and keeps the old value.
Is this a known bug? Any workaround? Or is it some kind of caching problem?
UPDATE
After trying to understand what happens, I found that this problem will occur when you have two different Java objects for the same entity. The null property will never be updated (but other properties with non-null values will).
Example code:
#Autowired
MovieRepository repository;
public void test() {
repository.deleteAll();
Movie movie1 = new Movie();
movie1.setName("Pulp Fiction");
movie1.setDirector("Quentin Tarantino");
movie1 = repository.save(movie1);
System.out.println("Movie1: " + movie1);
Movie movie2 = new Movie();
movie2.setId(movie1.getId());
movie2.setName(movie1.getName());
movie2.setDirector(null); // implicit...
movie2 = repository.save(movie2);
System.out.println("Movie2: " + movie2);
Movie movie3 = repository.findOne(movie1.getId());
System.out.println("Movie3: " + movie3);
}
Real life case: when using SDN with a Spring MVC form, it looks like entities are created from Model attributes. When a value is set to null in a form, the update is performed correctly in Neo4j, but the values are not returned correctly when using any find...() methods. Therefore it leads to stale data.
Side note: this problem happens when the Neo4J session scope is per "session" and doesn't happen when the session scope is per "request".
#Bean
#Override
#Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public Session getSession() throws Exception {
return super.getSession();
}
If you are using HttpSession-scoped persistence in SDN, you should ensure the the objects bound to your Controller via #ModelAttribute have the same scope as the persistence layer. Use the #SessionAttribute annotation on the Controller to achieve this.
If you use HttpRequest-scoped objects in your Controller and HttpSession-scoped persistence, you will get different objects representing the same graph entity at the web layer, and this will confuse the persistence mechanism.
Should not be a problem at all. I just tried
#Test
public void shouldPersistNulls() {
TempMovie movie = new TempMovie( "Pulp Fiction" );
tempMovieRepository.save( movie );
assertSameGraph( getDatabase(), "CREATE (m:Movie {name:'Pulp Fiction'})");
TempMovie loadedMovie = tempMovieRepository.findAll().iterator().next();
loadedMovie.setName(null);
tempMovieRepository.save(loadedMovie);
assertSameGraph( getDatabase(), "CREATE (m:Movie)");
TempMovie loadedAgainMovie = tempMovieRepository.findAll().iterator().next();
assertNull(loadedAgainMovie.getName());
}
and it passed.
Update based on edited question
The property representing the #GraphId must never be set manually i.e. via your code. You should load the entity by id when you require to update it. This ensures that the entity is known to the mapping context of the OGM and is managed correctly.

Flex data binding with View-Model pattern

I'm trying to move toward using the View/Model/View-Model or Presentation Model pattern in a Flex application since it definitely feels like the "correct" way to do things. I have a question about how something should work with Flex data binding though.
Say I have a Project model class which contains a bindable name field. I want to make a report to display information about the project. The title of the report should be [Project Name] Summary. I want to make a View-Model class to provide the backing for the report. This SummaryViewModel class will have a title field to provide the report title.
In my report mxml I would bind the title label to summaryModel.title, however title needs to somehow be bound to projectModel.name so if the name is changed in another part of the program the report title updates also.
What's the correct way to accomplish this "two-level" data binding in Flex? Should I be doing things a different way?
Let's say you have a model like this:
[Bindable]
public class Project {
public var name:String;
}
And you have your presentation model:
[Bindable]
public class SummaryPresentationModel
{
private var projectModel:Project = new Project();
public var title:String;
}
In your constructor, you can data bind the setter of the model to a function that sets the title:
public function SummaryPresentationModel() {
BindingUtils.bindSetter(modelNameChanged, projectModel, "name");
}
And then set the value of title:
private function modelNameChanged(newValue:String):void {
title = "[" + projectModel.name + "] Summary";
}
You are then free to bind to the summaryPM.title and everything will chain to the UI when projectModel.name changes.
You can get more complicated and use a "getter" function on title (as opposed to just setting it like I am here), but you need to propagate the change notification. I is not too terribly difficult to do, but I find that this method is a bit easier to follow.
Hope this helps!
No different than any other binding, they will both be updated (both being the place you're putting the title and the summary model).
If you post how you are defining your values I can help you with syntax, but this isn't a difficult binding operation. Where things get mildly more complicated would be with two way binding.

Resources