Data disappearing from the database? - grails

I am running a grails application and I am receiving the weirdest error I've probably ever encountered. One "field" in a model got data that just disappears for no reason.
I have two Model or a Domain class in my project with the following set up:
class Insertion {
String title
Date insertDate
static hasMany = Dataholder
static constraints = {
title(unique: true)
}
}
class Dataholder {
String product
int somenumber
int somenumber2
int somenumber3
Date startDate
Date endDate
List<String> somedatalist
Insertion insertions
static belongsTo = Insertion
static constraints = {
}
}
The "insertion" class is representing every time a user might input a bunch of dataholders. The dataholder represents all the data for that specific product. Important to know is that the data that disappears is contained in the Dataholder model and the ONLY data that disappears is the somedatalist.
This is the magic which is completely confusing, when I insert the data and saves it. It all goes well:
if (!errors) {
dataholderValidator.each {
it.insertion = insertion
it.save()
}
def results = Dataholder.findAllByInsertion(insertion)
I do some validating and apply data to every Dataholder and then if everything goes well, if(!errors) I add the insertion to each object. After that is done I save each objec, saving the data to the database. You may think it's going wrong here but just wait and be amazed.
After saving I get all the Dataholders from the database (since I want to be sure that the data was saved before printing it out to the user) by using the insertion. This is where the strange part begin, what I get back is the correct data:
results.each {
it.somedatalist.each { it2 ->
if(!weekdays.contains(it2))
weekdays.add(it2)
}
}
Populate an array with all the unique items from the datalist. Then printing it out to the view and voila:
Now, we just wait for the users confirm of all the data in the view and when he or she is clicking on a confirm button the insertion title is sent with post to function which would retrieve the data and to my surprise the somedatalist is null.
This is the functionality that retrieves the data:
def result = Insertion.findByTitle(insertionTitle)
def results = Dataholder.findAllByInsertions(result)
When putting a breaking point after results I can for sure confirm that every Dataholder contains the correct the right data except that somedatalist which is equal to null.
I've tried to get the data above by using the Insertion Title instead of just using the object and it works well. I can't understand why the data is populated in the database in one second and how something can just disappear?
Test:
void testSaveDataholder() {
Insertions insertion = new Insertion(title: 'adadad', insertDate: new Date())
insertion.save()
assert Insertion.all.size() == 1
Dataholder ed = new Dataholder(product: 'abc123', somenumber: 123, somenumber2: 13, startDate: new Date(), endDate: new Date(), somedatalist: ['TI'], insertions: insertion)
ed.save()
assert Dataholder.all.size() == 1
assert Dataholder.all.first().somedatalist.size() == 1
assert Dataholder.all.first().insertions.title == 'adadad'
assert Insertion.findAllByTitle('adadad').size() == 1
assert Dataholder.findAllByInsertions(Insertion.all.first()).size() == 1
}
This test all returns true, I am using Grails 2.1.
EDIT: I am using the in-memory database with "update" as configuration. So I can't really view the data. But it should be there.
Please help me with your sage advice and better wisdom.

It just has come to my mind. Persisting a collection of objects into single column breaks the 1st normal form, so it is not the correct way to do it. I have immediately googled an issue in JIRA:
http://jira.grails.org/browse/GRAILS-1023
The correct way is to create a new domain class with single String attibute and use standard one-to-many relation.

Related

Airtable Scripting block - Batch copy a field to another field in same table (10,000 records)

I'm trying to copy one field to another field in the same table with 10,000 + records, in batches of 50 using the Scripting App.
What am I doing wrong in this code block? It only copies the first record. If I remove the await, it'll copy 15 records then stop.
let table = base.getTable('Merchants');
let view = table.getView('Grid view');
let query = await view.selectRecordsAsync();
let records = query.records;
updateLotsOfRecords(records);
async function updateLotsOfRecords(records) {
let i = 0;
while (i < records.length) {
const recordBatch = records.slice(i, i + 50);
for (let record of recordBatch) {
let sourceValue = record.getCellValue('Merchant');
await table.updateRecordAsync(record, { 'LogoBase64': sourceValue });
}
i += 50;
}
}
you should use updateRecordsAsync function, not updateRecordAsync
When using single update function in loop, there is no sense to divide it into batches.
You exceed some limit of calls per second, that's why it stops.
For multiple updates, you need to use updateRecordsAsync, like this
while (recordsToWrite.length > 0) {
await updates.updateRecordsAsync(recordsToWrite.slice(0, 50));
recordsToWrite = recordsToWrite.slice(50);
}
Data that you should pass to it, more complex. I learned JS for 3 months and still have difficulties understandins all these "arrays of arrays of objects, passed via object's property". But that's the key to unerstand JS.
It's quite hard to leave basic/pascal habits, with plenty of inserted FOR loops, and GOTO sometimes))
I think, you already found the answer for 2 months, so my answer may be useless, but when i write it here, maybe i understand it better for myself. And help to some beginners also.
For single write, you pass (record, Object), where object is {field:'Value}
For multiple, you should pass
Array of Objects, where
Object is {id:recordID, fields:{object2}} , where
object2 is array of obj3 [ {obj3},{obj3}, {obj3} ], where
obj3 is a { 'Name or ID of field': fieldvalue }
you script might be:
let query = await view.selectRecordsAsync();
let updates=query.records.map(rec=>{
Map method can be applied for arrays, and 'query.records' is array of records. Here
'rec' is loop variable inside this "arrowfunction"
now let's create obj3 , in our case { 'Name or ID of field': fieldvalue }
{'LogoBase64':rec.getCellValue('Merchant')}
wrap it into fields property
fields:{'LogoBase64':rec.getCellValue('Merchant')}
and add record id
wrapping as Object.
To avoid complex string with linebreaks, and to make object creation easier, we can do it with function:
{rec.id, fields:{'LogoBase64':rec.getCellValue('Merchant')}}
fuction myObj(rec){return {rec.id, fields:{'LogoBase64':rec.getCellValue('Merchant')}}
map(rec=>myObj(rec)) - can be written as map(myObj)
we need array of objects, and map method gets first array, doing something with each element and return other array, of results. like we need.
and now finally we get
let table = base.getTable('Merchants');
let view = table.getView('Grid view');
let query = await view.selectRecordsAsync();
function myObj(rec){return {'id':rec.id,'fields':{'Logobase64':rec.getCellValue('Merchant')}}};
let updates=query.records.map(myObj);
while (updates.length > 0) {
await table.updateRecordsAsync(updates.slice(0, 50));
updates = updates.slice(50); }

Filtering Realm with nested subqueries

My app has data that looks like this.
class ShelfCollection: Object {
let shelves: List<Shelf>
}
class Shelf: Object {
let items: List<Item>
}
class Item: Object {
var name: String
let infos: List<String>
}
I'm trying to get all shelves in a shelf collection where any items match the query either by name or by an element in their infos list. From my understanding this predicate should be correct, but it crashes.
let wildQuery = "*" + query + "*"
shelfResults = shelfCollection.shelves.filter(
"SUBQUERY(items, $item, $item.name LIKE[c] %# OR SUBQUERY($item.infos, $info, info LIKE[c] %#).#count > 0).#count > 0",
wildQuery, wildQuery
)
It complies as a NSPredicate, but crashes when Realm is attempting to parse it, throwing me
'RLMException', reason: 'Object type '(null)' not managed by the Realm'
I suspect the nested subquery might be what fails, but I don't know enough about NSPredicate to be sure. Is this an acceptable query, and how can I make it.. work?
This is an answer and a solution but there's going to be a number of issues with the way the objects are structured which may cause other problems. It was difficult to create a matching dataset since many objects appear within other objects.
The issue:
Realm cannot currently filter on a List of primitives
EDIT: Release 10.7 added support for filters/queries as well as aggregate functions on primitives so the below info is no longer completely valid. However, it's still something to be aware of.
so this Item property will not work for filtering:
let infos: List<String>
However, you can create another object that has a String property and filter on that object
class InfoClass: Object {
#objc dynamic var info_name = ""
}
and then the Item class looks like this
class Item: Object {
var name: String
let infos = List<InfoClass>()
}
and then you filter based on the InfoClass object, not it's string property. So you would have some objects
let info0 = InfoClass()
info0.info_name = "Info 0 name"
let info1 = InfoClass()
info1.info_name = "Info 1 name"
let info2 = InfoClass()
info2.info_name = "Info 2 name"
which are stored in the Item->infos list. Then the question
I'm trying to get all shelves in a shelf collection...
states you want to filter for a collection, c0 in this case, shelves whose items contain a particular info in their list. Lets say we want to get those shelves whose items have info2 in their list
//first get the info2 object that we want to filter for
guard let info2 = realm.objects(InfoClass.self).filter("info_name == 'Info 2 name'").first else {
print("info2 not found")
return
}
print("info2 found, continuing")
//get the c0 collection that we want to get the shelves for
if let c0 = realm.objects(ShelfCollection.self).filter("collection_name == 'c0'").first {
let shelfResults = c0.shelves.filter("ANY items.infoList == %#", info2)
for shelf in shelfResults {
print(shelf.shelf_name)
}
} else {
print("c0 not found")
}
I omitted filtering for the name property since you know how to do that already.
The issue here is the infos could appear in many items, and those items could appear in many shelf lists. So because of the depth of data, with my test data, it was hard to have the filter return discreet data - it would probably make more sense (to me) if I had example data to work with.
Either way, the answer works for this use case, but I am thinking another structure may be better but I don't know the full use case so hard to suggest that.

parse.com Storing a specific value once

I'm new to the Parse api and am trying to figure out how to do the following:
My app stores strings ("foo", "bar", etc). "foo" should only exist once no matter how many times users attempt to add it - along with a count of how many times that string was attempted to be added. Thus if four users attempt to add the string "foo" I'd like the associated PFObject to look like:
name: "foo"
count: 4
(there should never be more than one object with a name of "foo")
I know what I could query for "foo", retrieve it, and then update the count but I have a feeling that a race condition would exist if multiple users are trying to update "foo" at the same time.
What is the right/best way to achieve this via the Parse API (I'm using iOS if it matters).
Parse cloud code beforeSave. https://parse.com/docs/cloud_code_guide#functions-modifysave
Before a save occurs, check for the existence of the row, and update it, then return response.error()
Something like this:
Parse.Cloud.beforeSave("MyObject", function(request, response) {
var newObject = request.object;
if(!newObject.existed()) {
var query = new Parse.Query("MyObject");
var name = newObject.get("name");
query.equalTo("name", name);
query.first().then(function(existing){
if(existing){
existing.increment("count");
return existing.save().then(function(){
response.error(name + " already exists");
});
}
else {
response.success();
}
});
}
else {
response.success();
}
});
Parse provides you with an incrementKey method that helps you avoiding problems when multiple users trying to update a counter. You could also decrement or increment by a given amount if needed. They call it Counters. But this only solves the race condition problem.
[myString incrementKey:#"count"];
[myString saveInBackground];
You can find more information here: https://www.parse.com/docs/ios_guide#objects-updating/iOS.

Entity Framework is not returning the proper data. It is repeating data from a single record

Using MVC 4 with EF code First.
When doing linq to EF selects statements, the collections are being populated with what seems like the last record's data. And what's weirder, only some of the properties are repeated where others are not. It is best to show you by example:
Using this query returns the proper data:
var orders = db.Orders.ToList();
OrderID OrderTotal Name
1 215.00 Bob
2 415.00 Mark
3 315.50 Ralph
When I filter the Orders entity by a SubscriberID, which is a foreign key, like so:
var orders = db.Orders.Where(s => s.SubscriberId == 2).ToList();
The data end up looking like this:
1 315.50 Bob
2 315.50 Mark
3 315.50 Ralph
Notice how the OrderTotal is repeated but the names stay the same. Please note that this is not a view issue. When I look at the data in the collection while debugging in the controller, this is what I see. This does not appear to be the only place this is happening. I am seeing something similar with more complicated models - but I thought I'd start with the simplest sample. Thanks!
The problem was caused when I was setting default values on my models. Apparently using static was incorrect. So:
[ReadOnly(true)]
[Display(Name = "Sub total")]
private static decimal _OrderSubTotal = 0;
public decimal OrderSubTotal { get { return _OrderSubTotal; } set { _OrderSubTotal = value; } }
Should be written as
[ReadOnly(true)]
[Display(Name = "Sub total")]
private decimal _OrderSubTotal = 0;
public decimal OrderSubTotal { get { return _OrderSubTotal; } set { _OrderSubTotal = value; } }

Entry state showing different values when read directly and when read from a variable

I am using entity framework 4.1 and code first in asp.net mvc. Just to test learn i wrote below code (A controller).
public ActionResult Foo()
{
StringBuilder sb = new StringBuilder();
using (var db = new DemoDataBase1Context())
{
//get person from db
var person = db.Persons.FirstOrDefault();
//get entry
var entry = db.Entry(person);
//now change the person object
person.Name = "Some New Value";
//print entity state
//this is showing unchanged
sb.Append("<br>State: " + entry.State);
//this is showing changed
sb.Append("<br>State: " + db.Entry(person).State);
}
return Content(sb.ToString());
}
In above code you can see, when iam doing entry.State its saying unchanged, if i do db.Entry(person).State its saying changed. Can any one explain why??
If you have auto change detection enabled (which is the default in EF 4.1) Entry calls DetectChanges internally. The method starts probably similar to this:
if (Configuration.AutoDetectChangesEnabled)
ChangeTracker.DetectChanges();
//...
In your second call of db.Entry(person) the object has changed and the DetectChanges method detects this by comparing a snapshot which was made when you loaded the entity with the current values. Since there is a difference the state changes from Unchanged to Modified.
Also the State of the entry object you have created before the change will go to Modified because DbEntityEntry.State is likely a property which just propagates the State value of the inner _internalEntityEntry which remains the same instance in both DbEntityEntry objects.
If you really want to save the former state of an entity you need to save the State itself, not only the entry object:
var state = db.Entry(person).State;
This is just an enum and won't change with a later call to Entry.
You can compare this behaviour with the behaviour when you disable automatic change detection:
db.Configuration.AutoDetectChangesEnabled = false;
Both sb.Append... lines will receive the state Unchanged in that case because EF doesn't notice now anymore that one of your POCO properties has changed because DetectChanges isn't called.
I think the Entry method gives you the state of the object as it is when you call Entry. I don't think it has anything to do with reading it from a variable versus calling it directly.
When you get your reference to the first entry, your object isn't changed. The very next line you change it and call Entry again, at which point it is changed. If you store a reference to that then compare the two I am guessing they are different references:
var person = db.Persons.FirstOrDefault();
// get reference to entry - unchanged at this point
var entry1 = db.Entry(person);
// make a change to the object
person.Name = "Changed";
// get reference to entry - changed now
var entry2 = db.Entry(person);
// these will not be equal: probably false
var equalOrNot = entry1 == entry2;

Resources