Why is java.lang.Long not persistable? - google-cloud-datastore

I am trying to query for a list of ids of type Long in GAE/JDO. And I'm getting the following exception when I call detachCopyAll() on the result set.
org.datanucleus.jdo.exceptions.ClassNotPersistenceCapableException: The class "The class "java.lang.Long" is not persistable. This means that it either hasnt been enhanced, or that the enhanced version of the file is not in the CLASSPATH (or is hidden by an unenhanced version), or the Meta-Data/annotations for the class are not found." is not persistable. This means that it either hasnt been enhanced, or that the enhanced version of the file is not in the CLASSPATH (or is hidden by an unenhanced version), or the Meta-Data for the class is not found.
at org.datanucleus.jdo.NucleusJDOHelper.getJDOExceptionForNucleusException(NucleusJDOHelper.java:241)
at org.datanucleus.jdo.JDOPersistenceManager.jdoDetachCopy(JDOPersistenceManager.java:1110)
at org.datanucleus.jdo.JDOPersistenceManager.detachCopyAll(JDOPersistenceManager.java:1183)
...
I can query for a list of User objects and detach them just fine. I expected all primitive wrapper classes like Long to be persistable. What am I doing wrong? Below is the code I'm working with.
#PersistenceCapable(identityType=IdentityType.APPLICATION, detachable="true")
public class User
{
#PrimaryKey
#Persistent(valueStrategy=IdGeneratorStrategy.IDENTITY)
private Long id;
private String email;
}
#SuppressWarnings("unchecked")
public static List<Long> getUserKeys(String email)
{
assert email != null;
List<Long> keyList = null;
PersistenceManager pm = null;
Query query = null;
try {
pm = PMF.get().getPersistenceManager();
query = pm.newQuery("select id from " + User.class.getName());
query.declareParameters("String emailParam");
query.setFilter("email == emailParam");
List<Long> resultList = (List<Long>) query.execute(email);
// next line causes the ClassNotPersistenceCapableException
keyList = (List<Long>) pm.detachCopyAll(resultList);
}
finally {
if (query != null) query.closeAll();
if (pm != null) pm.close();
}
return keyList;
}

List<Long> resultList = (List<Long>) query.execute(email);
// next line causes the ClassNotPersistenceCapableException
keyList = (List<Long>) pm.detachCopyAll(resultList);
I don't understand what you are doing here. A List<Long> does not have to be detached. You'd want to detach instances of your User entity class, but a Long is a Long, and you can just do whatever you need to do with the resultList.
The error message is confusing, but just caused by Long not being an entity class.

Related

Dapper question. Getting values from returned object

Just started learning Dapper. I have an ADO.NET background. Using a demo I downloaded, I can insert/delete data from a webform into a MySql table just fine. This, however, I have searched all morning on.
In retrieving a single row from the db by ID, it doesn't return a LIST<>, it seems to be just an object (using code from the demo I downloaded). The query works, I get the object back. It has the fields: "ProductID, Description and Price".
The only way I could get the values to those three fields was like this:
System.Reflection.PropertyInfo pi = Product.GetType().GetProperty("ProductID");
System.Reflection.PropertyInfo desc = Product.GetType().GetProperty("Description");
System.Reflection.PropertyInfo price = Product.GetType().GetProperty("Price");
int _ProductID = (int)(pi.GetValue(Product, null));
string _Description = (string)(desc.GetValue(Product, null));
decimal _Price = (decimal)(price.GetValue(Product, null));
This works and gets the correct values for the three fields.
I'm used to looping through DataTables, but I just think there is probably a better way to get those values.
Is this the correct way to do this or am I missing something? I did actually read documentation and mess with this all morning before asking, too.
Some of the things I looked at seem to be very complex. I thought Dapper was supposed to simplify things.
OK, Thanks Marc. It was difficult for me to see what was supposed to be in the Dapper class files and what was supposed to be in my code behind. The original demo way of getting a product by ID had the query as .FirstOrDefault();
I changed everything to return a List<> and it all worked. I'm sure my ADO.NET is showing, but this works. In Dapper class files:
public List<Product> ProductAsList(int Id)
{
return this._db.Query<Product>("SELECT * FROM Cart_product WHERE ProductID=#Id", new { Id = Id }).**ToList()**;
}
This is just getting one row that matched the ProductID.
In page codebehind:
protected void CartItemAdd(string ProductId) // passing it the selected ProductID
{
var results = cartservice.ProductAsList(Convert.ToInt32(ProductId));
// returns that one row using Dapper ProductAsList(ProductId)
int _ProductId = 0;
string Description = string.Empty;
decimal Price = 0;
// Loop through the list and get the value of each item:
foreach (Product obj in results)
{
_ProductId = obj.ProductID;
Description = obj.Description;
Price = obj.Price;
}
// Using Dapper to insert the selected product into the shopping cart (table):
String UserName = "jbanks";
cartitem = new CartItem();
cartitem.ProductID = _ProductId;
cartitem.Quantity = 1;
cartitem.Description = Description;
cartitem.Price = Price;
cartitem.Created = DateTime.Now;
cartitem.CreatedBy = UserName;
result = cartservice.AddCartItem(cartitem);
if (result)
{
lblMessage.Text = string.Empty;
lblMessage.Text = "Successfully added a cart item";
}
}
}
It does indeed look up the product from one table and insert a selected item into another table.
Thanks again!
The main Query<T> API returns an IEnumerable<T>, which often will be a List<T>; the AsList<T>() extension method can get it back to a list without a copy, but either way: they are just T, for whatever T you asked for. If you asked for Query<Product>, then: they should be Product instances:
var results = connection.Query<Product>(someSql, someArgs); // perhaps .AsList()
foreach (Product obj in results) { // "var obj" would be fine here too
// now just use obj.ProductID, obj.Description and obj.Price
}
If that didn't work: check that you used the <T> version of Query. There is a non-generic variant too, which returns dynamic. Frankly, you should almost always use the <T> version.
Note: I'm assuming that somewhere you have something like
class Product {
public int ProductID {get;set;}
public string Description {get;set;}
public decimal Price {get;set;}
}

MemoryCache.Default.AddOrGetExisiting returns null although the key is in the cache

I am writing unit tests for my asp.net web API application and one of them is trying to verify that AddOrGetExisting is working correctly. According to the MSDN documentation, AddOrGetExisting returns an item if it's already saved, and if not it should write it into Cache.
The problem I am having is that if I add the key to MemoryCache object from an unit test, then call AddOrGetExisting, it will always return null and overwrite the value instead of returning the value that is already saved. I am verifying that the value is in the cache right before I call AddOrGetExisting(bool isIn evaluates to true).
Here is the code for my memory cache and the test method. Any help would be much appreciated:
public static class RequestCache
{
public static TEntity GetFromCache<TEntity>(string key, Func<TEntity> valueFactory) where TEntity : class
{
ObjectCache cache = MemoryCache.Default;
var newValue = new Lazy<TEntity>(valueFactory);
CacheItemPolicy policy = new CacheItemPolicy { AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(60) };
bool isIn = cache.Contains(key);
// Returns existing item or adds the new value if it doesn't exist
var value = cache.AddOrGetExisting(key, newValue, policy) as Lazy<TEntity>;
return (value ?? newValue).Value;
}
}
public string TestGetFromCache_Helper()
{
return "Test3and4Values";
}
[TestMethod]
public void TestGetFromCache_ShouldGetItem()
{
ObjectCache cache = MemoryCache.Default;
CacheItemPolicy policy = new CacheItemPolicy { AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(60) };
var cacheKey = "Test3";
var expectedValue = "Test3Value";
cache.AddOrGetExisting(cacheKey, expectedValue, policy);
var result = Models.RequestCache.GetFromCache(cacheKey,
() =>
{
return TestGetFromCache_Helper();
});
Assert.AreEqual(expectedValue, result);
}
The issue may be that you're passing a Lazy<TEntity> as newValue within RequestCache.GetFromCache but passing a string as expectedValue in the test method.
When running the test, the cache.Contains(key) confirms that there is a value stored for that key, which is true. However it is a string instead of a Lazy<TEntity>. Apparently AddOrGetExisting decides to overwrite the value in that case.
The fix for this particular scenario may be to adjust the expectedValue assignment in your test to something like this:
var expectedValue = new Lazy<string>(TestGetFromCache_Helper);
You'd also need to pull the value from the Lazy in the test's final equality comparison, for example:
Assert.AreEqual(expectedValue.Value, result);

OrientDB execute script asynchronously and fetch records in a lazy fashion

Currently, we are using the Document API in OrientDB version 2.2. Let us suppose we have a class Company and a class Employee. Let's suppose we are interested in all Companies with at least one employee having a name from an arbitrary list. Employees are defined as LINKEDLISTs in our Company schema.
Our query would look smth like this:
select from Company where employees in (select from Employee where name in ["John", "Paul"])
Currently we have defined the following two indexes:
Company.employees (index on the employee links (their #rid)) -> dictionary hash index and
Employee.name -> notunique index
When executing the above query with explain we see that only the second index Employee.name is used, since we did not define the above indexes as a compound index. AS far as I could understand compound indexes across different classes like in our case are not supported in Orient 2.x.
Queries like this:
select from Company let $e = select from employees where name in ["John", "Paul"] where employees in $e
do not solve our problem either.
Searching across different blogs revealed two suggestions so far:
trying to define a compound index via inheritance by introducing a parent class on employee and company and defining the above two indexes on that
https://github.com/orientechnologies/orientdb/issues/5069
bundle the two queries in a batch scrip like this:
https://github.com/orientechnologies/orientdb/issues/6684
String cmd = "begin\n";
cmd += "let a = select from Employees where name " + query + "\n";
cmd += "let b = select from Company where employees in $a\n";
cmd += "COMMIT\n";
cmd += "return $b";
Suggestion 1 did not work for us.
Suggestion 2. worked. Both indexes have been used in each separate query, but then we ran into the next limitation of Orient. Batch scripts seem to be executed only synchronously, meaning that we can only get the results as a list all at once and not one by one in a lazy fashion, which in our case is a NO GO due to the memory overhead.
One naive workaround we tried is as follows:
public class OCommandAsyncScript extends OCommandScript implements OCommandRequestAsynch{
public OCommandAsyncScript(String sql, String cmd) {
super(sql, cmd);
}
#Override
public boolean isAsynchronous() {
return true;
}
private void containsAtLeastOne(final #Nonnull ODatabaseDocumentTx documentTx,
final #Nonnull Consumer<Company> matchConsumer,
final #Nonnull String queryText
) throws TimeoutException {
String cmd = "begin\n";
cmd += "let a = select from Employee where name " + queryText + "\n";
cmd += "let b = select from Company where employees in $a\n";
cmd += "COMMIT\n";
cmd += "return $b";
final OCommandHandler resultListener = new OCommandHandler(documentTx, (document -> {
final Company companies = document2model(document);
matchConsumer.accept(company);
}));
OCommandAsyncScript request = new OCommandAsyncScript("sql", cmd);
request.setResultListener(resultListener);
documentTx.command(request).execute();
...
}
}
public class OCommandHandler implements OCommandResultListener {
private final ODatabaseDocumentTx database;
private final Consumer<ODocument> matchConsumer;
public OCommandHandler(
final #Nonnull ODatabaseDocumentTx database,
final #Nonnull Consumer<ODocument> matchConsumer
) {
this.database = database;
this.matchConsumer = matchConsumer;
}
#Override
public boolean result(Object iRecord) {
if (iRecord != null) {
final ODocument document = (ODocument) iRecord;
/*
Result handler might be asynchronous, if document is loaded in a lazy mode,
database will be queries to fetch various fields. Need to activate it on the current thread.
*/
database.activateOnCurrentThread();
matchConsumer.accept(document);
}
return true;
}
...
}
The approach of defining a custom OCommandAsyncScript did not work unfortunately. When debugging the OStorageRemote class of Orient it seems that no partial results could be read, Here the respective extract from the source code:
public Object command(final OCommandRequestText iCommand) {
....
try {
OStorageRemote.this.beginResponse(network, session);
List<ORecord> temporaryResults = new ArrayList();
boolean addNextRecord = true;
byte status;
if(asynch) {
while((status = network.readByte()) > 0) {
ORecord record = (ORecord)OChannelBinaryProtocol.readIdentifiable(network);
if(record != null) {
switch(status) {
case 1:
if(addNextRecord) {
addNextRecord = iCommand.getResultListener().result(record);
database.getLocalCache().updateRecord(record);
}
break;
case 2:
if(record.getIdentity().getClusterId() == -2) {
temporaryResults.add(record);
}
database.getLocalCache().updateRecord(record);
}
}
}
}
}
Network.readbyte() is always null, hence no records could be fetched at all.
Is there any other workaround how we could execute a sql script in asynchronus mode and retrieve results in a lazy fashion preventing the generation of large lists on our application side?

BindingResult.getFieldValue() returning null in test context for a formatted value

In a spring mvc app, I submit id's and use a formatter to convert that id to an object. It works well in the container.
But in the unit test environment, I'm seeing a problem.
I mock the formatter to always return my test value, this is fine it gets injected into the ModelAttribute. But in the BindingResult, a call to result.getFieldValue("location") for example is returning null, but only in the MockMvc context.
This is the test case:
/**
* Tests the inventory update for existing inventory records.
* #throws Exception
*/
#Test
public void testUpdateExistingProductInventory() throws Exception{
logger.entry();
VariantInventory oldInventory = new VariantInventory();
oldInventory.setId(20l);
Product product = ProductBuilder.buildBasicExisting();
Location location = new Location();
location.setId(3l);
ProductVariant variant = new ProductVariant();
variant.setId(2l);
// check the formatter is working
Mockito.when(mockProductFormatter.parse(((String)Mockito.anyObject()), ((Locale)Mockito.anyObject()))).thenReturn(product);
Product p = mockProductFormatter.parse("1", null);
Assert.assertEquals(p, product);
// check the formatter is working
Mockito.when(mockLocationFormatter.parse(((String)Mockito.anyObject()), ((Locale)Mockito.anyObject()))).thenReturn(location);
Location l = mockLocationFormatter.parse("3", null);
Assert.assertEquals(l, location);
// check the formatter is working
Mockito.when(mockVariantFormatter.parse(((String)Mockito.anyObject()), ((Locale)Mockito.anyObject()))).thenReturn(variant);
ProductVariant pv = mockVariantFormatter.parse("2", null);
Assert.assertEquals(pv, variant);
// check the formatter is working
Mockito.when(mockInventoryFormatter.parse(((String)Mockito.anyObject()), ((Locale)Mockito.anyObject()))).thenReturn(oldInventory);
VariantInventory v = mockInventoryFormatter.parse("20", null);
Assert.assertEquals(v, oldInventory);
this.mockMvc.perform(MockMvcRequestBuilders.post("/ajax/products/update/inventory")
.param("product", "1")
.param("variant", "2")
.param("location", "3")
.param("status", "ACTIVE")
.param("quantityOnHand", "30.5")
.param("lowStockQuantity", "10")
.param("inventory", "20")
)
.andExpect(status().isOk());
Mockito.verify(mockInventoryService, Mockito.times(1)).updateExisting(Mockito.eq(oldInventory), Mockito.any(VariantInventory.class));
logger.exit();
}
This is the relative part of the controller:
#RequestMapping(value = "/ajax/products/update/inventory", method= RequestMethod.POST)
public #ResponseBody
AJAXResponse updateProductInventory(#ModelAttribute ProductInventoryFormWrapper formWrapper, BindingResult result,
ModelMap map) {
logger.entry();
logger.debug("Getting product data");
if (!result.hasErrors()) {
inventoryValidator.validate(formWrapper, result);
}
}
Then skipping a few items, this is the relevant validation that fails, where I am passing location as the field.
ValidationUtils.rejectIfEmptyOrWhitespace(errors, field, "required.field", new String[]{label});
The object fails to validate because of what must be a bug.
What I observe if I debug the controller is:
The object is in the FormWrapper, and the properties are there.
But in the BindingResult object, if I call 'getFieldValue('location')` which is what's being called in the spring validation code, it's returning null, and therefore the validator rejects the value.
So for some reason the binding result hasn't registered the formatted fields or something. Note that this only happens in the Unit Test, not in the container.
Does anyone know how to fix?
Quick Edit:
I've done some more debugging, and it's failing in this block of code from AbstractPropertyBindingResult. The value is okay right up until the conversionService is called to convert it. I haven't downloaded the source beyond that method, so I can't see exactly why it's failing, but somewhere in the convert method it's being turned from the proper value, to null. I presume because I'm using MockObjects, and maybe it's calling something that I haven't anticipated to return the value.
#Override
protected Object formatFieldValue(String field, Object value) {
String fixedField = fixedField(field);
// Try custom editor...
PropertyEditor customEditor = getCustomEditor(fixedField);
if (customEditor != null) {
customEditor.setValue(value);
String textValue = customEditor.getAsText();
// If the PropertyEditor returned null, there is no appropriate
// text representation for this value: only use it if non-null.
if (textValue != null) {
return textValue;
}
}
if (this.conversionService != null) {
// Try custom converter...
TypeDescriptor fieldDesc = getPropertyAccessor().getPropertyTypeDescriptor(fixedField);
TypeDescriptor strDesc = TypeDescriptor.valueOf(String.class);
if (fieldDesc != null && this.conversionService.canConvert(fieldDesc, strDesc)) {
return this.conversionService.convert(value, fieldDesc, strDesc);
}
}
return value;
}
Ok that was a tough one, so I didn't really expect anyone to answer. But here's the answer. I was right, the Mock was being called in the validation. So I had to add an additional mock method to the formatters (print):
// check the formatter is working
Mockito.when(mockInventoryFormatter.parse(((String)Mockito.anyObject()), ((Locale)Mockito.anyObject()))).thenReturn(oldInventory);
// this was added
Mockito.when(mockInventoryFormatter.print(Mockito.any(VariantInventory.class), Mockito.any(Locale.class))).thenReturn("20");

Code practice to handle empty result set in Linq to custom list

My Question is how do I handle a null set returned from a linq query if I am loading it into a custom class.
example
queryResults = queryResults.Select(p => new specialItems(p.ID, p.SECTION, p.PROGRAM, p.EVENT).ToList<specialItems>();
...
public class specialItems
{
public string Id { get; set; }
public string Section { get; set; }
public string Program { get; set; }
public string Event { get; set; }
public courseItems(string id, string section, string program, string event)
{
this.Id = id;
this.Section = section;
this.Program = program;
this.Event = event;
}
}
Currently this query works great until the result set is empty, then I get:
"Object reference not set to an instance of an object."
I need the query to return an empty List if the result set is empty.
UPDATE - Asided from the invalid redeclaration of a variable (fixed) I did find that the issue was higher up in the initial construction of the linq query. This became apparent when I received several good suggestions and removed the error. Once I fixed the original query things worked swimmingly.
Use the null coalescing operator (??).
List<specialItems> queryResults = queryResults.Select(p => new specialItems(p.ID, p.SECTION, p.PROGRAM, p.EVENT).ToList<specialItems>() ?? new List<specialItems>();
EDIT: Yeah, looking at what you have there a little closer, it's the ToList that's blowing up when this happens. You might have to split it up a bit.
var temp = queryResults.Select(p => new specialItems(p.ID, p.SECTION, p.PROGRAM, p.EVENT);
List<specialItems> results = temp == null ? new List<specialItems>() : temp.ToList<SpecialItems>();
Have to do it this way, because there's no good spot to put the null coalescing operator in this case.
Robaticus is mostly right, use the null coalescing operator (??). Howerver, since you didn't include the stack trace, I assume your code is throwing because queryResults is initially null. By the time you get to the ?? operator, you've already thrown the exception, because you tried to dereference queryResults.
Also, the code you have doesn't make a ton of sense, because queryResults is already defined within that scope by the time you get to that line. You can't redefine a variable that has already been declared locally in that scope.
List<SpecialItems> queryResults = GetSomeResults();
queryResults = (queryResults ?? new List<SpecialItems>())
.Select(p => new SpecialItems(p.ID, p.SECTION, p.PROGRAM, p.EVENT))
.ToList<SpecialItems>();
If you can get the function or line that spits out the original version of queryResults to return an empty list instead of null, then try to do that, or coalesce the results on that line. That's probably better than having all that code on the query line :)
List<SpecialItems> queryResults = GetSomeResults() ?? new List<SpecialItems>();
queryResults = queryResults
.Select(p => new SpecialItems(p.ID, p.SECTION, p.PROGRAM, p.EVENT))
.ToList<SpecialItems>();
Linq returns an empty list if there are no results, never null. Therefore, the problem is certainly not that queryResults.Select() returns null.
What is probably going on is that we're looking at a lazily evaluated linq-to-objects 'query'. ToList() triggers the evaluation of it, and probably the nullreference exception occurs in a lambda expression higher up the chain.
Neither Enumerable.Select, nor Queryable.Select, nor Enumerable.ToList return null.
The query is not realized until ToList enumerates it. During that enumeration, a null reference exception is occuring due to code you have not posted in the question.
Consider this code with and without the commented line:
List<int> source = Enumerable.Range(1, 10).ToList();
IEnumerable<int> query = null;
try
{
query = source.Where(i => 1 / i > 0);
}
catch(Exception ex)
{
Console.WriteLine("Exception was caught {0}", ex.Message);
}
// source.Add(0);
List<int> result = query.ToList();
Consider this code with and without the commented line:
DataContext myDC = new DataContext();
string name = null;
IQueryable<Person> query = myDC.Persons.Where(p => p.Name.StartsWith(name));
// name = "Zz";
List<Person> result = query.ToList();

Resources