EBeans update does not save changed field items - jpa

I upgrade from Play 2.5 to 2.7, and am having a problem with saving my forms.
When fields are changed and I call the Model.update() the changes are not persisted in the database (even though they show changed when debugging before the update is done)
When however I set them specifically, then they do persists. So it must have to do something with the fact that it does not detect the change and does not see the object as changed. I use getter and setters in the model, and all the properties are private.
This is the controller function (with the two lines to persist those two fields)
#Check(UserTask.MANAGER)
public Result updateSceneSet(Http.Request request) {
Messages messages = messagesApi.preferred(request);
Form<StreamingSceneSet> form = formFactory.form(StreamingSceneSet.class).bindFromRequest(request);
if (form.hasErrors()) {
if (form.rawData().get("id") != null && form.rawData().get("id").length() > 0) {
long itemId = Long.parseLong(form.rawData().get("id"));
StreamingSceneSet item = StreamingSceneSet.findById(itemId);
return badRequest(views.html.streaming.editSceneSetView.render(form, item, messages, request));
} else {
return badRequest(views.html.streaming.createSceneSetView.render(form,messages, request));
}
}
// Form is OK, has no errors we can proceed
StreamingSceneSet item = form.get();
item.setName(item.getName());
item.setDescription(item.getDescription());
// Insert or update?
if (item.getId() == null) {
item.insert();
flash("success", messages().at("addedSceneSet", item.getName()));
} else {
item.update();
flash("success", messages().at("updatedSceneSet", item.getName()));
}
return redirect(routes.Streaming.sceneSets());
}

It seems because when I started the upgrade I had some legacy classes I didn't have getters and setters, and as I had some issue I put in:
play.forms.binding.directFieldAccess = true
Removing this made everything work again.

Related

Jetpack Paging3 RemoteMediator returns same PagingSatate on #load append

I'm following this codelab to build an paging3 app with github API and a local DB. While the first 2 pages load fine, the mediator hits a loop when trying to load the 3rd page when scrolling to bottom - the same PagingState is passed to load() function over and over.
Just wondering if anyone knows what could be the possible root cause here?
Some implementation details:
RemoteMediator: (the prevPage and currentPage is from github API's pagination response header and saved to a local DB.)
// RepositoryMediator
override suspend fun load(
loadType: LoadType,
state: PagingState<Int, Repository>
): MediatorResult {
return when (loadType) {
LoadType.REFRESH -> {
fireRequestForPage(1, true /*clear DB*/)
return Success(endOfPaginationReached = false)
}
LoadType.APPEND -> {
// !!!!!!! kept getting the same state when APPEND is triggered, resulting in same currentPage and nextPage
// get currentPage, nextPage from state.lastItemOrNull
if(currentPage < nextPage) {
fireRequestForPage(nextPage)
Success(endOfPaginationReached = false)
} else {
return Success(endOfPaginationReached = true)
}
LoadType.PREPEND -> {
// get currentPage, prevPage from state.firstItemOrNull
if(currentPage > prevPage) {
fireRequestForPage(prevPage)
Success(endOfPaginationReached = false)
} else {
return Success(endOfPaginationReached = true)
}
}
}
}
Observable: I'm using liveData instead of flow to from the Pager:
fun searchRepositoryWithUserId(userLoginName: String): LiveData<PagingData<Repository>> {
// need to create a new Pager each time because the search query is different
return Pager(
config = PagingConfig(pageSize = PAGE_SIZE, enablePlaceholders = false),
remoteMediator = RepositoryMediator()
) {
repoDao().getRepositoriesOfUser(userLoginName)
}.liveData
}
Dao: just a plain query
#Query("SELECT * FROM repository_table WHERE login = :ownerLoginName")
fun getRepositoriesOfUser(ownerLoginName: String): PagingSource<Int, Repository>
For anyone interested, the fix is from Dao, need to update the query to sort on reponame, otherwise the query will return the same last Page for PagingSource even if there're new items inserted into DB, confusing the Mediator.
#Query("SELECT * FROM repository_table WHERE login = :ownerLoginName ORDER BY repository_name ASC")
fun getRepositoriesOfUser(ownerLoginName: String): PagingSource<Int, Repository>
Had a similar issue just now. Trying to sort by different fields had led to RemoteMediator getting stuck in a loop on different page numbers.
Turns out I couldn't rely on item ID's assigned by backend to be primary keys for my Room DB Entity. Assigning primary key ID's locally (starting from zero) seems to have fixed the issue.

Mark an order as "Full Payment" on Sage 200

I am inserting orders on Sage 200 through an application using the client side, C# and APIs.
I would like to check the "Full payment" checkbox on the "Payment with order" tab.
Currently, I am setting the PaymentType property, which is not working.
order.PaymentType = Sage.Accounting.SOP.SOPOrderPaymentTypeEnum.EnumSOPOrderPaymentTypeFull;
order is an instance of Sage.Accounting.SOP.SOPOrder.
Do you know how I can check that property?
The following method should supply the required results.
private static void SetPaymentWithOrder(Sage.Accounting.SOP.SOPOrder sopOrder)
{
// Indicate that order has payment
sopOrder.PaymentWithOrder = true;
// This is full payment order
sopOrder.PaymentType = Sage.Accounting.SOP.SOPOrderPaymentTypeEnum.EnumSOPOrderPaymentTypeFull;
// Fetch the the Payment Methods. SOPPaymentMethods contructor accepts the boolean flag whether to fetch payment methods including card processing method or not.
Sage.Accounting.SOP.SOPPaymentMethods paymentMethodsCollection = new Sage.Accounting.SOP.SOPPaymentMethods(false);
// Set the first payment method of the collection to the order
sopOrder.PaymentMethod = paymentMethodsCollection.First;
}
dont know if you ever managed to figure this one out or not.
Not sure if you knew this, but you cannot modify the Sales Order on the view form, or at least shouldn't be trying to do so.
Using either of the Enter/Amend Sales Order forms will allow you to do so.
What is potentially happening, is that the properties that the controls are bound to are not updating the UI after your code has run.
You can simply force this to happen using the following
Fetching the underlying bound object
public Sage.Accounting.SOP.SOPOrderReturn SOPOrderReturn
{
get
{
//Loop over the boundobjects collection
//check if the bound object is of the type we want - e.g. SOPOrderReturn
//if correct type, return this object
Sage.Common.Collections.BoundObjectCollection boundObjects = this.form.BoundObjects;
if (boundObjects != null)
{
foreach (object boundObject in boundObjects)
{
if (boundObject is Sage.Accounting.SOP.SOPOrderReturn)
{
this._sopOrderReturn = boundObject as Sage.Accounting.SOP.SOPOrderReturn;
break;
}
}
}
return this._sopOrderReturn;
}
}
Fetch the correct underlying form type that the amendable form is, suspending the databinding,
perform your changes,
resuming the databinding
Sage.MMS.SOP.MaintainOrderForm maintainOrderForm = this.form.UnderlyingControl as Sage.MMS.SOP.MaintainOrderForm;
maintainOrderForm.BindingContext[this.SOPOrderReturn].SuspendBinding();
this.SOPOrderReturn.PaymentWithOrder = true;
this.SOPOrderReturn.PaymentType = Sage.Accounting.SOP.SOPOrderPaymentTypeEnum.EnumSOPOrderPaymentTypeFull;
maintainOrderForm.BindingContext[this.SOPOrderReturn].ResumeBinding();
should do the trick.

Caching a result from EF

I have this method for retrieving a result from my context and caching it using MemoryCache.
public IEnumerable<CustomerRole> GetCustomerRoles()
{
string key = String.Format(CC_CACHE_CUSTOMER_ROLE_ALL, "all");
return _cacheManager.Get(key, () =>
{
return from r in _customerRoleRepository.Table select r;
}
);
}
I then use this in my view like
#foreach (CustomerRole role in Model)
{
}
The problem I have is that because the actual result isn't executed until the data is accessed (in my view), it's not actually caching the result.
How do I force this query to run via my caching function rather than waiting until the data is used?
I've not included what _cacheManager.Get() does as I know it's caching whatever I send to it properly but if you think that is the problem, let me know and I will post the relative code.
Note: I have tried doing it this way hoping it would force the query to run but still no luck
public IEnumerable<CustomerRole> GetCustomerRoles()
{
string key = String.Format(CC_CACHE_CUSTOMER_ROLE_ALL, "all");
return _cacheManager.Get(key, () =>
{
var roles = from r in _customerRoleRepository.Table select r;
return roles.Take(roles.Count());
}
);
}
You need to call a method like ToList() to force linq to get the data. Then just add that list to your cache.

Why do iOS keychain values not change without leaving the ViewController?

I have an abstraction on the iOS Keychain API that seems to work well. Basically, it has:
public string GetGenericPasswordField(string account)
{
var record = SecKeyChain.QueryAsRecord(query, out code);
if (code == SecStatusCode.ItemNotFound)
return null;
return NSString.FromData(record.ValueData, NSStringEncoding.UTF8);
}
public void SetGenericPasswordField(string account, string value)
{
if (value == null)
{
SecKeyChain.Remove(record);
return;
}
var record = new SecRecord (SecKind.GenericPassword) {
Service = service,
Label = label,
Account = account,
ValueData = NSData.FromString (value),
};
SecStatusCode code = SecKeyChain.Add (record);
if (code == SecStatusCode.DuplicateItem)
{
// (remove and re-add item)
}
}
I have used this abstraction on my app's settings screen to save values while leaving, and then load those values elsewhere in the app.
But I've run into an issue where saving a value does not appear to take effect if you don't leave the current ViewController. What I'm doing is analogous to:
if (Keychain.GetGenericPasswordField("RemoteLogin") == null)
{
var remotePassword = GetFromDialog();
Keychain.SetGenericPasswordField("RemoteLogin", Hash(remotePassword));
// Safe to assume the RemoteLogin password got saved, right?
}
// Later on...
if (Keychain.GetGenericPasswordField("RemoteLogin") == null)
{
// This block is being executed
}
I've stepped through the code in the debugger to confirm that things are as I'm describing them, and that my abstraction method really is getting a SecStatusCode.ItemNotFound back, meaning null is the appropriate value to return.
I worked around this once by moving the first half of my code back to a previous ViewController, and for some reason that seemed to wake it up, or clear out whatever caching is taking place. But now I've encountered another situation where that's not really practical.
Why is this happening? Is my abstraction leaking?

The given key was not present in the dictionary

I am developing a plugin in crm 5.0 to retrieve date "ct_valuedate" from an entity called "ct_marketvalue" and formatting and saving in a field called "ct_dateserial"
I get an error while I debug "The given key was not present in the dictionary"
public class MarketValueDateFormatting : PluginBase
{
protected override void ExecutePlugin()
{
try
{
switch (_crmMessage)
{
case CrmPluginMessageEnum.Create:
if (_context.InputParameters.Contains("ct_marketvalue"))
{
//Obtain the logical name of the entity
string moniker1 = ((EntityReference)_context.InputParameters["EntityMoniker"]).LogicalName;
//Verify that the target entity represents an Account.
//If not, this plug-in was not registered correctly.
if (moniker1.Equals("ct_marketvalue"))
{
Entity marketvalueimage = (Entity)_context.PostEntityImages["ct_marketvalue"];
Guid marketvalueid = marketvalueimage.Id;
if (marketvalueimage.Contains("ct_valuedate"))
{
DateTime dateserial = (DateTime)marketvalueimage.Attributes["ct_valuedate"];
String dateserialstring = dateserial.ToString("YYYYMMdd");
Ct_marketvalue marketvalue = new Ct_marketvalue();
marketvalue.Ct_dateserial = dateserialstring;
marketvalue.Id = marketvalueid;
_serviceContext.UpdateObject(marketvalue);
}
}
}
break;
}
catch (Exception ex)
{
throw ex;
}
}
}
}
Few notes about your code.
You should check in your code that _context.PostEntityImages contains "ct_marketvalue". It's possible either to forgot register or to do a mistake in image name.
Might be better use .ToEntity rather than access attributes using .Attributes["ct_valuedate"].
I'm not sure what is purpose of the plugin you wrote, but it looks it is post stage plugin and it updates the same entity instance, that was in InputParameters. Might be better to make this plugin pre stage and update value directly in InputParameters. Because, if not "The given key was not present in the dictionary" exception, it will cause infinite loop. You will need check context.Depth.