Saving 2 versions of an entity at the same time - jpa

I'm currently trying to implement a CRUD-Application für Orders/Articles in JSF/Primefaces.
Whenever I create a new version of an article I want to merge the old entity with a different status and save the new entity populated by form input with a new ID.
This is the relationship between Article and OrderLine:
The Article Entity has the following field:
#OneToMany(cascade = CascadeType.ALL, mappedBy = "fkArticleID")
#XmlTransient
private Collection<OrderLine> orderLineCollection;
This is the method that updates/saves the new Entity:
public void edit(Article article) throws OptimisticLockException {
/* PK des Auftrags/der Auftragsposition speichern um die Suche zu vereinfachen */
int articleID = article.getArticleID();
/**
*
* Falls sich article im Zustand "detached" befindet, werden in
* attachedArticle die aktuellen Daten aus der DB geladen.
*
* Falls sich orderLine im Zustand "managed" befindet, werden in
* attachedOrderLine die Daten aus dem PersistenceContext geladen. Dies
* ist notwendig, da nur Datensätze für Entities gesperrt werden können
* die sich im Zustand "managed" befinden.
*
*/
Article attachedArticle = em.find(Article.class, articleID, LockModeType.OPTIMISTIC);
/* Prüfen ob der Artikel noch in der Datenbank vorhanden ist */
if (attachedArticle != null) {
/* Laden des aktuellsten Datensatzes aus der Datenbank */
Article latestVersionArticle = findLatestVersion(articleID);
/* Anhand der Version wird geprüft ob die bearbeiteten Daten noch konsistent mit dem Zustand der Datenbank sind */
if (latestVersionArticle.getVersion() == article.getVersion()) {
/**
* Schreibt den bearbeiteten Artikel zurück in die Datenbank,
* Versionsnummer wird am Ende der Transaktion automatisch
* inkrementiert (optimistische Sperre)
*/
latestVersionArticle.setArticleStatus(ArticleStatus.GESPERRT);
em.merge(latestVersionArticle);
/**
* Erstellt einen neuen Artikel mit den eingegebenen Daten und
* dem Status Freigegeben.
*/
article.setArticleStatus(ArticleStatus.FREIGEGEBEN);
article.setOrderLineCollection(null);
em.persist(article);
} else {
/* OptimisticLockException werfen falls die Daten des Auftrags nicht mehr konsistent sind */
throw new OptimisticLockException(article);
}
} else {
throw new OptimisticLockException(article);
}
}
Everything seems to work fine at first.. however the newer Version of the article seems to automatically create another OrderLine which shows up in the existing Order.. so whenever I "update" an article, while the newer version is created, it is also creating another OrderLine.. I suspect the fault lies with the #OneToMany field in the Article-Entity.. I'm trying to set the orderLineCollection to null before persisting but it doesnt seem to work.

You have to remove cascading on the orderLineCollection.
If you persist an article, you'll always get duplicates of the existing orderLines.
Please also consider to remove the bidirectional relationship between Article and OrderLine. Usually you only need a unidirectional relationship from OrderLine to Article. If you need all OrderLines for an article, you can use a NamedQuery.

Related

TYPO3 form extension - finishers create multiple entries in YAML

The form extension in TYPO3
finishers create multiple entries in the YAML file.
Don't know exactly why this happens.
Also got multiple mails for confirmation after sending a form.
defaultValue: ''
type: Text
identifier: text-1
label: Objektname
properties:
fluidAdditionalAttributes:
required: required
validationErrorMessages:
-
code: '1221560910'
message: 'Wir brauchen den Namen des Objektes.'
-
code: '1221560718'
message: 'Wir brauchen den Namen des Objektes.'
-
code: '1347992400'
message: 'Wir brauchen den Namen des Objektes.'
-
code: '1347992453'
message: 'Wir brauchen den Namen des Objektes.'
validators:
-
identifier: NotEmpty
-
defaultValue: ''
type: Text
identifier: text-2
label: Anlage
properties:
fluidAdditionalAttributes:
required: required
validationErrorMessages:
-
code: '1221560910'
message: 'Um was für eine Anlage handelt es sich?'
-
code: '1221560718'
message: 'Um was für eine Anlage handelt es sich?'
-
code: '1347992400'
message: 'Um was für eine Anlage handelt es sich?'
-
code: '1347992453'
message: 'Um was für eine Anlage handelt es sich?'

Add marker to multiple layer groups

I have created a map with leafletjs using StyledLayerControl and markercluster:
https://www.wiva.at/v2/basemap-kartentest/
Each marker represents a research project that fits in one category (=layergroup).
Unfortunately I have some projects that fall into three categories (like the very south one near the city LEIBNITZ close to GRAZ). So far this one project is represented as three markers, and I got the feedback this confuses especially in the spiderfied view.
I've come across an issue, when assigning my marker to a variable and then adding the variable to multiple layergroups that unselecting one layergroup makes the marker disappear in the other layer groups as well.
So is there any chance to represent such a project as ONE marker but appearing in multiple layer groups?
If the link above is not sufficient I can add my code (but I'm afraid it's kind of messy).
Thanks for any hint.
EDIT:
So far I add my marker simply like that:
//Green Industry projects
//new (running) projects
var industry_new = new L.LayerGroup();
//Renewable Gasfield, laufend, Wiva, ONLINE
L.marker([46.753278, 15.586361], {icon: industryIcon} ).addTo(industry_new).bindPopup("<p><span style='font-size:12pt;font-weight:bold; color:#0099b8;'>Renewable Gasfield</span></p><b>Projektleitung:</b> Energie Steiermark<br /><b>Standort:</b> Gabersdorf<br /><b>Kategorie:</b> Grüne Industrie<br /><b>Status:</b> laufend<br /><p>Ganzheitlicher Power-to-Gas Ansatz, bei dem aus erneuerbarem Strom durch Elektrolyse grüner Wasserstoff erzeugt wird und eine zweistufige katalytische Methanisierung im großen Maßstab für eine nachhaltige Energieversorgung in den Bereichen Energie, Mobilität und Industrie vereint.</p><a href='https://www.wiva.at/v2/portfolio-item/renewable-gasfield/'>Details...</a>");
//HyTechbasis 4 WIVA, laufend, Wiva, ONLINE
L.marker([48.155278, 14.048056], {icon: industryIcon} ).addTo(industry_new).bindPopup("<p><span style='font-size:12pt;font-weight:bold; color:#0099b8;'>HyTechbasis 4 WIVA</span></p><b>Projektleitung:</b> FRONIUS INTERNATIONAL GmbH<br /><b>Standort:</b> Thalheim<br /><b>Kategorie:</b> Grüne Industrie<br /><b>Status:</b> laufend<br /><p>Hydrogen Technology Basis for WIVA</p><a href='https://www.wiva.at/v2/portfolio-item/hytechbasis-4-wiva-hydrogen-technology-basis-for-wiva/'>Details...</a>");
//Co2EXIDE WIVA, laufend, Wiva, ONLINE
L.marker([48.33826938809515, 14.317320611066839], {icon: industryIcon} ).addTo(industry_new).bindPopup("<p><span style='font-size:12pt;font-weight:bold; color:#0099b8;'>CO2EXIDE</span></p><b>Projektleitung:</b> (österreichischer Partner) Energieinstitut an der JKU Linz<br /><b>Standort:</b> AGH Krakau Demo-Anlage<br /><b>Kategorie:</b> Grüne Industrie<br /><b>Status:</b> laufend<br /><p>CO2-basierte Elektrosynthese von Ethylen Oxiden</p><a href='http://www.co2exide.eu/'>Details...</a>");
//CORALIS WIVA, laufend, Wiva, ONLINE
L.marker([48.288029, 14.324497], {icon: industryIcon} ).addTo(industry_new).bindPopup("<p><span style='font-size:12pt;font-weight:bold; color:#0099b8;'>CORALIS</span></p><b>Projektleitung:</b> Fundación CIRCE / Öst. Partner: Energieinstitut an der JKU Linz<br /><b>Standort:</b> Linz<br /><b>Kategorie:</b> Grüne Industrie<br /><b>Status:</b> laufend<br /><p>Erfahrungen im Bereich der Industriesymbiose zusammenstellen</p><a href='https://cordis.europa.eu/project/id/958337'>Details...</a>");
//UpHY, laufend, Wiva, ONLINE
L.marker([48.14735053624901, 16.492216234765525], {icon: industryIcon} ).addTo(industry_new).bindPopup("<p><span style='font-size:12pt;font-weight:bold; color:#0099b8;'>UpHy I</span></p><b>Projektleitung:</b> OMV<br /><b>Standort:</b> Wien<br /><b>Kategorie:</b> Grüne Mobilität<br /><b>Status:</b> laufend<br /><p>Im Project UpHy I wird die Basis für die Demonstration der Wertschöpfungskette für die grüne H2- Mobilität von der Produktion in einer Elektrolyse über die Logistik bis zur 350 bar Betankungsinfrastruktur für eine kommerziell betriebene Buslinie mit Brennstoffzellenantrieb entwickelt.</p><a href='https://www.wiva.at/v2/portfolio-item/uphy-upscaling-of-green-hydrogen-for-mobility-and-industry/'>Details...</a>");
//Underground Sun.Conversion, laufend, Wiva-Netzwerk
L.marker([48.028889, 13.691944], {icon: industryIcon} ).addTo(industry_new).bindPopup("<p><span style='font-size:12pt;font-weight:bold; color:#0099b8;'>Underground Sun.Conversion</span></p><b>Projektleitung:</b> RAG Austria AG<br /><b>Standort:</b> Pilsbach<br /><b>Kategorie:</b> Grüne Industrie<br /><b>Status:</b> abgeschlossen<br /><p>Chemical storage of renewable energy in porous subsurface reservoirs with exemplary testbed</p><a href='https://www.underground-sun-conversion.at/'>Details...</a>");
I do that for each layer group. Probably this is not the best way, but for me as a java and leaflet beginner the easiest way and I was just very happy everything worked out so far ;-)
Unfortunately that is an unresolved UX issue. The main issue is that in some use cases, you want an OR filter (sounds like it would be your case, since your Markers are duplicated in each group where they fit the associated category); and in others, you want an AND filter...
So if you want to populate your map with all Markers that fit at least one selected category (i.e. implement an OR filter), a possible solution could be to use "dummy" empty Layer Groups for your selection control, clear and re-populate the map with relevant Markers whenever the user selection changes.
For example, if you have the map "overlayadd/remove" events:
// "Dummy" layers to be used in selection control
const dummy1 = L.layerGroup();
const dummy2 = L.layerGroup();
// Actual categories with possibly common Markers
const category1 = L.layerGroup([markerA, markerB]);
const category2 = L.layerGroup([markerA, markerC]);
// Intermediate group to easily clear map content
const content = L.layerGroup().addTo(map);
map.on("overlayadd overlayremove", () => {
// Step 1: remove all content
content.clearLayers();
// Step 2: re-add layers that fit at least one selection
if (map.hasLayer(dummy1)) {
category1.addTo(content)
}
if (map.hasLayer(dummy2)) {
category2.addTo(content)
}
// etc.
});
In case you use Leaflet.markercluster, you can simply use it as the content variable in above snippet.
You also have to create only 1 Marker per project, no longer duplicate them for each category. In normal use cases, this should be avoided, but here we specifically handle this case. For example if Marker A matches categories 1 and 2, you can do:
L.marker(latLngA).addTo(category1).addTo(category2);

Auto fill some fields in form when you found id of other form, odoo 8.0

I try to create a simple function who try to fill specific fields in own form when I select the ID of patient registered in other form/module. I put an example:
Module Registro:
(create patient)
(automatic generation ID and visible)
-Nombre:
-Email:
-Teléfono:
(save)
Admisión module:
(Open new form)
-ID: select id
(function for auto fill the next fields)
-Nombre: nombre (registro)
-Email: email(registro)
-Teléfono: teléfono(registro)
Use the new API Odoo 8.0 I try this, but doesn't work with message: error 500 type.
función autocompletar campos
#api.onchange('telefono_contacto','persona_contacto','email','nombre_acompanante') # mete campos a afectar
def autofill(self):
# comdición; si esta con el id seleccionado
# self.id_anamnesis
# llenar los campos con los correspondientes del id
# self.telefono_contacto =''
# self.persona_contacto = ''
# self.email = ''
# self.nombre_acompanante = ''
pass # aquí la lógica
(La plataforma es Odoo 8.0, S.O: Ubuntu 14.04)
Thank you and best reegards,
Marco García Baturan.
product_id = fields.Many2one("myproduct.model",string="Product", required=True)
description = fields.Char("Description", related="product_id.description", store=True)
It is done using related="......"
What I have done is When I select my product it will automatically
set description of that particular product.
So you need to add related where you want to auto fill.
If you set store=True then description is store into database.

How-to: Setup Azure Push Notification with Client SDK v3.1.0 and Server SDK v2.0.0 using a CustomAuthController

Since a few days the new Azure Server and Client SDK are available. I had that issue with the App Service Push https://github.com/Azure/azure-mobile-apps-net-server/issues/170#issuecomment-262656329 in last November 2016.
After reading the release blog https://blogs.msdn.microsoft.com/appserviceteam/2017/01/10/azure-mobile-apps-net-sdk-releases/ I can now see that the current
way to register for push notification is deprecated.
Can you please give me detailed instructions what I have to change to use the new App Service Push?
The previous problem was that the
_UserId (SID)
Tag was not properly included in the push notification installation. The _UserId had the MD5 hash of the NameIdentifier instead of the clients unique Id I passed to the CustomAuthController. But I need my clients unique Id afterwards for targeted push notifications to clients utilizing the
_UserId=client-unique-id
Here is my current code in Android:
protected override void OnRegistered(Context context, string registrationId)
{
Log.Verbose("PushHandlerBroadcastReceiver", "GCM Registered: " + registrationId);
App.NotificationHubInstallationId = registrationId;
//await RegisterForPushNotifications(OfflineSyncStoreManager.Instance.MobileAppClient, MainActivity.CurrentActivity);
MainActivity.CurrentActivity.RunOnUiThread(async () =>
{
if (GcmClient.IsRegistered(context))
{
try
{
var pushHub = OfflineSyncStoreManager.Instance.MobileAppClient.GetPush();
const string templateBodyGcm = "{\"data\":{\"message\":\"$(messageParam)\"}}";
var templates = new JObject
{
["genericMessage"] = new JObject
{
{"body", templateBodyGcm}
}
};
//NOTE: Unregister any previous NotificationHub Installation of the TruckerApp on that device
await pushHub.UnregisterAsync().ConfigureAwait(false);
//NOTE_ Register the TruckerApp for Push Notification in the backend.
await pushHub.RegisterAsync(registrationId, templates).ConfigureAwait(false);
MetricsManager.TrackEvent($"PushNotificationHub-{OfflineSyncStoreManager.Instance.MobileAppClient.CurrentUser.UserId}",
new Dictionary<string, string>
{
{"NotificationHubInstallationId", registrationId}
},
new Dictionary<string, double>());
Log.Info("Push Installation Id", App.NotificationHubInstallationId);
}
catch (Exception ex)
{
await MetricsManagerHelper.Instance.SendErrorToApplicationInsightsAsync($"PushNotificationHub Registration failed for reason: {ex.Message}");
DialogNotify("AZURE PUSH Registierungsfehler", "Pushmeldungen sind derzeit nicht verfügbar. " + Environment.NewLine + Environment.NewLine +
"Um neue Aufträge auf Ihr Handy zu übertragen ziehen " +
"Sie bitte in der Truck Auftrag Übericht (hier!) " +
"mit dem Finger von OBEN -> nach -> UNTEN." +
Environment.NewLine +
Environment.NewLine);
}
}
else
{
await MetricsManagerHelper.Instance.SendErrorToApplicationInsightsAsync("GCM/FCM Client is not registered at Google");
DialogNotify("GCM/FCM Push Registrierungsfehler", "Sei konnten nicht beim Google Cloud Messaging angemeldet werden. " +
"Versuchen Sie bitte ein ReLogin oder um neue Aufträge " +
"auf Ihr Handy zu übertragen, ziehen " +
"Sie bitte in der Truck Auftrag Übericht (hier!) " +
"mit dem Finger von OBEN -> nach -> UNTEN." +
Environment.NewLine +
Environment.NewLine);
}
});
}
Here is my current code in iOS:
// We've successfully registered with the Apple notification service, or in our case Azure
public override async void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
{
try
{
const string templateBodyApns = "{\"aps\":{\"alert\":\"$(messageParam)\"}}";
JObject templates = new JObject();
templates["genericMessage"] = new JObject
{
{"body", templateBodyApns}
};
// Register for push with your mobile app
Push push = OfflineSyncStoreManager.Instance.MobileAppClient.GetPush();
await push.RegisterAsync(deviceToken, templates);
}
catch (Exception e)
{
UIAlertView avAlert = new UIAlertView("AZURE PUSH Registierungsfehler",
"Pushmeldungen sind derzeit nicht verfügbar. " +
Environment.NewLine +
Environment.NewLine +
"Um neue Aufträge auf Ihr Handy zu übertragen ziehen " +
"Sie bitte in der Truck Auftrag Übericht (hier!) " +
"mit dem Finger von OBEN -> nach -> UNTEN." +
Environment.NewLine +
Environment.NewLine,
null,
"OK",
null);
avAlert.Show();
}
}
Thanks in advance,
Eric
You don't need to unregister and then register - a simple register will do it.
Check out chapter 5 of the book - http://aka.ms/zumobook - there is code within the chapter for each type of push registration that covers the Installation method (where you specify tags and templates together). You can then specify the SID explicitly by constructing a tag that is suitable for your needs.
One save way is to use the Azure Mobile Client installationId, persist it in your backend and use that Id for targeted push notifications to that individual client. Instead sending the push notification to _UserId:your-userid post to $installationId:your-clients-zumo-client-id
But that requires you to store the installationId in your backend SQL Server or other cache (e.g. Redis)
A better solution is to follow both links below:
General App Service Push Notification Installations ZUMO Book
and for custom push notification Tags that Custom Tag Blog

Add alt attribute to ALL links in Typo3

I'm currently making a website accessible. Currently, there are only the title attributes defined of each link. For maximum compatibility with screen readers, I need to have the alt and the title.
Is there a way to add to each link the alt attribute with the value of the title? Best would be typoscript.
Another problem is, that the site is online and frequently visited. It has to be a method which is 100% working.
found here : http://typo3-4-newbies.blogspot.co.at/2014/03/image-alt-text-so-hinterlegen-sie-einen.html
// Löscht die Standard-Konfiguration des Alt-Textes
tt_content.image.20.1.altText >
// Neuaufbau als TEXT-Objekt
tt_content.image.20.1.altText = TEXT
tt_content.image.20.1.altText {
// zusätzliches Objekt zur Fallunterscheidung leer/befüllt
// (zugegeben: erst nach längerem herumprobieren war das die finale Lösung)
cObject = TEXT
// Das Objekt erhält den Wert aus dem Feld "alternative Text",
// den Sie direkt beim Bild eintragen können
cObject.field = altText
// Wenn kein Alt-Text hinterlegt wurde, wird ein TEXT-Objekt erzeugt
ifEmpty.cObject = TEXT
ifEmpty.cObject {
// Ich ersetze nun Teile des Original-Dateinamens
// Da ich es übersichtlich mag, teile ich mir meine Funktion ein wenig auf
replacement {
10 {
// Sucht alle Werte zwischen "/" und entfernt diese
search = /\/(.*)\//
useRegExp = 1
replace =
}
15 {
// Danach entferne ich die Dateiendung
// Somit steht nur noch der reine Name der Datei da
search = /^(.*)\.(.*)/
useRegExp = 1
replace = $1
}
20 {
// zuletzt lösche ich die voranstehenden Punkte,
// sollten diese von TYPO3 gesetzt worden sein
search = ..
replace =
}
}
// Den Wert (hier der Dateiname plus Pfad) beziehe ich aus dem Feld "image" des Inhaltselements
field = image
// Da im Feld "image" die Bilder durch Komma getrennt in der Datenbank abgespeichert werden,
// führe ich einen Optionsplit mit Komma als Trennzeichen durch. Damit kann ich jedes einzelne Bild entsprechend bearbeiten.
// Tun Sie dies nicht, haben aber mehrere Bilder, so würde der Alt-Text des letzten Bildes bei allen anderen angezeigt werden
split.token.char = 44
// Gibt je das aktuelle Bild zurück
split.returnKey.data = register : IMAGE_NUM_CURRENT
}
}
// Vererbung der neuen Alt-Text Definitionen auf das Inhaltselement "Text mit Bild"
tt_content.textpic.20.1.altText.ifEmpty.cObject < tt_content.image.20.1.altText.ifEmpty.cObject