GAE JPA Illegal argument when trying to edit entites from query - google-app-engine

i am breaking my self with this problem and i would need some help. I am trying to edit queries but i keep getting this error
javax.persistence.PersistenceException: Illegal argument
...
Caused by: java.lang.IllegalArgumentException: operating on too many entity groups in a single transaction.
...
this is the part of code i use to update records
final EntityManager em = PersistenceManager.getInstance().getEntityManagerFactory().createEntityManager();
try {
//em.getTransaction().begin();
{
Query q = em.createQuery(String.format("SELECT FROM %s cat", NewsContent.class.getSimpleName()));
int count = 0;
for(NewsContent nc : (List<NewsContent>) q.getResultList()){
nc.setOrderTimestamp(nc.getTimestamp());
count++;
}
resp.setContentType("text/plain");
resp.getWriter().println("NewsContent:\n\t Updated " + count + " records\n" );
}
//em.getTransaction().commit()
} finally {
//if(em.getTransaction().isActive())
// em.getTransaction().rollback();
em.close();
}
this is the part from persistance.xml
<provider>org.datanucleus.api.jpa.PersistenceProviderImpl</provider>
<properties>
<property name="datanucleus.NontransactionalRead" value="true"/>
<property name="datanucleus.NontransactionalWrite" value="true"/>
<property name="datanucleus.ConnectionURL" value="appengine"/>
<property name="datanucleus.appengine.datastoreEnableXGTransactions" value="true"/>
<property name="datanucleus.singletonEMFForName" value="true"/>
</properties>
and this is JPA Entity(I removed setters and getters)
#Entity
public class NewsContent {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
Key ID;
String api_key;
String author_username;
String author_displayname;
String organization;
String organization_displayname;
long timestamp;
String api_type;
long order_timestamp;
Text text = null;
String title = null;
String title2 = null;
String extra = null;
String extra_desc = null;
Boolean featured = false;
String category = null;
String imageID = null;
String image_serving_url = null;
}
Any idea?

Your JPQL is incorrect.
SELECT FROM %s cat
It should be
Select cat from %s cat
A common format of jpql that picks all the columns from a table.
select o from TableName o where o.id=1
If you wish to pick a single column, then it will be
select o.colName from TableName o where o.id=1

Related

How should I write my connection string?

I am newbie with Nhibernate. I have installed NHibernate by using NuGet.
There are a lot of tutorials on NHibernate, but most of them are really old(all of them are presented with Microsoft VS 2008). Except for this from TutorialsPoint. So I tried to follow this tutorial step by step. This is my Program.cs:
class Program
{
static void Main(string[] args)
{
var cfg = new Configuration();
String DataSource = "(localdb)\\MSSQLLocalDB";
String InitialCatalog = "TutorialsPointDb";
String IntegratedSecurity = "True";
String ConnectTimeout = "30";
String Encrypt = "False";
String TrustServerCertificate = "False";
String ApplicationIntent = "ReadWrite";
String MultiSubnetFailover = "False";
cfg.DataBaseIntegration(x =>
{
x.ConnectionString = DataSource + InitialCatalog + IntegratedSecurity + ConnectTimeout + Encrypt +
TrustServerCertificate + ApplicationIntent + MultiSubnetFailover;
x.Driver<SqlClientDriver>();
x.Dialect<MsSql2008Dialect>();
});
cfg.AddAssembly(Assembly.GetExecutingAssembly());
var sefact = cfg.BuildSessionFactory();
using (var session = sefact.OpenSession())
{
using (var tx = session.BeginTransaction())
{
var student1 = new Student
{
ID = 1,
FirstMidName = "Allan",
LastName = "Bommer"
};
var student2 = new Student
{
ID = 2,
FirstMidName = "Jerry",
LastName = "Lewis"
};
session.Save(student1);
session.Save(student2);
tx.Commit();
}
Console.ReadLine();
}
}
}
These code that I just qoute is almost identical with the tutorial from tutorialspoint(the solution name is differ). And I have this Exception:
System.ArgumentException: Format of the initialization string does not
conform to specification starting at index 0
from this line: var sefact = cfg.BuildSessionFactory();
And after research, from my understanding this exception was caused of bad ConnectionString. But my x.ConnectionString is just identical with the instruction and I can not understand that what did I miss.
And I am awared of that normally there will by a data name: hibernate.cfg.xml in the solution with settings like these:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2" >
<session-factory>
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
<property name="connection.connection_string">Data Source=localdb\mssqllocaldb;Initial Catalog=TutorialsPointDb</property>
<property name="show_sql">false</property>
<property name="dialect">NHibernate.Dialect.MsSql2008Dialect</property>
<mapping assembly="DataTransfer"/>
</session-factory>
</hibernate-configuration>
But not in this step: Create Data from NHibernate - Basic CRUD Operations part.
So my question is, what did I miss? And how can I resolve this Exception?
Thank you for reading.
Other Exceptions that I got:
Exception thrown: 'System.IO.FileNotFoundException' in mscorlib.dll
Exception thrown: 'System.ArgumentException' in System.Data.dll
Exception thrown: 'System.ArgumentException' in NHibernate.dll
An unhandled exception of type 'System.ArgumentException' occurred in
NHibernate.dll
Other codes from my project in case you want to check for yourself.
My Database:
CREATE TABLE [dbo].[Student]
(
[ID] INT NOT NULL PRIMARY KEY IDENTITY,
[LastName] NVARCHAR(MAX) NULL,
[FirstMidName] NVARCHAR(MAX) NULL
)
This is my one class Student.cs
namespace TutorialsPoint
{
public class Student
{
public virtual int ID { get; set; }
public virtual string LastName { get; set; }
public virtual string FirstMidName { get; set; }
}
}
And its Student.hbm.xml file
<?xml version = "1.0" encoding = "utf-8" ?>
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2"
assembly = "TutorialsPoint" namespace = "TutorialsPoint">
<class name = "Student">
<id name = "ID">
<generator class = "native"/>
</id>
<property name = "LastName"/>
<property name = "FirstMidName"/>
</class>
</hibernate-mapping>
The exception
System.ArgumentException: Format of the initialization string does not conform to specification starting at index 0
is related to statement:
...But my x.ConnectionString is just identical with the instruction and I can not understand that what did I miss...
Because, the code is declaring params:
String DataSource = "(localdb)\\MSSQLLocalDB";
String InitialCatalog = "TutorialsPointDb";
String IntegratedSecurity = "True";
...
which cannot be just concatenated
x.ConnectionString = DataSource + InitialCatalog
+ IntegratedSecurity + ConnectTimeout
+ Encrypt + ...
Because that would lead to result:
"(localdb)\\MSSQLLocalDBTutorialsPointDbTrue...
But we need something like this:
x.ConnectionString = $"DataSource={DataSource};"
+ $"InitialCatalog={InitialCatalog};"
+ $"IntegratedSecurity={IntegratedSecurity}"
+ ...
to get
"DataSource=(localdb)\\MSSQLLocalDB;InitialCatalog=TutorialsPointDb;..
And that would result in the expected connection string format:
key1=value1;key2=value2;key3=value3;...

JPA hibernate insert row cause ConstraintViolationException

i have simple entity class:
#Entity
#Table(name = "NH_ENTITIES")
#Getter
#Setter
#ToString
public class Entita {
/**
* Primary key.
*/
#Id
#Column(name = "PK", nullable = false, length = NHConstants.DB_STANDARD_LENGTH)
#GeneratedValue(strategy = GenerationType.AUTO, generator = "nh_entities_gen")
#SequenceGenerator(name = "nh_entities_gen", sequenceName = "NH_ENTITIES_SEQ", initialValue = 1, allocationSize = 1)
private int pk;
/**
* Entity name.
*/
#NotEmpty(message = "Entita je povinná")
#Size(max = NHConstants.DB_MAX_LENGTH, message = "Maximální počet znaků: " + NHConstants.DB_MAX_LENGTH)
#Column(name = "ENTITY", unique = true, nullable = false, length = NHConstants.DB_MAX_LENGTH)
private String entity = "";
/**
* For Hibernate only.
*/
public Entita() {
}
}
and my service method:
#Override
#Transactional(readOnly = false, propagation = Propagation.REQUIRED)
public void saveEntity(Entita entity) {
log.debug("Start transaction saveEntity");
this.entityRepo.save(entity);
log.debug("Transaction saveEntity finished");
}
when i manually insert row/rows to this entity by some sql client and afterthat execute saveEntity programatically im getting the error
could not execute statement; SQL [n/a]; constraint [C##NH.SYS_C0013920]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
This error im getting just once....it depends how many rows i inserted before manually....
Is there another way how to handle this issue except execute findlast before save?
Thank you for your suggestion.
I resolved my issue. i inserted exactly the numbers sequencially in DB
It is neccessary to use the sequence for this purpose.

JPA query return List<org.datanucleus.store.types.sco.backed.ArrayList> instead List<T>

I'm using JPA on GAE and this query return a List containing 1 element.
This element is a org.datanucleus.store.types.sco.backed.ArrayList (and it's finally containing my results) while I'm expecting a List of Products. What I'm doing wrong?
Thanx in advance!
Query query = entityManager.createQuery
("select p.products from Place p where p.id = :Id" );
query.setParameter("Id",id);
List<Product> resultList = query.getResultList();
//for debugging purpose
assert (resultList.get(0) instanceof Product);
if (resultList.size() > 0)
{
//raise a cast exception here
Product p = resultList.get(0);
}
#Entity
public class Place {
private Collection<Product> products;
#OneToMany(cascade = CascadeType.ALL)
public Collection<Product> getProducts() {
return products;
}
public void setProducts(Collection<Product> products) {
this.products = products;
}
private String id;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Extension(vendorName="datanucleus", key="gae.encoded-pk", value="true")
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
Selecting a multi-valued field from a JPQL query is illegal when the JPQL spec says the select item should be
"single_valued_path_expression | scalar_expression | aggregate_expression |
identification_variable | OBJECT(identification_variable) | constructor_expression"
so answers saying this query is correct are wrong. If you want the "products" for a Place then you retrieve the Place and it has the products.
I am not much familiar with DataNucleus, so haven't executed. But with JPA, the query should work fine. You can try the below code to build query, which returns results according to the specified class.
entityManager.createQuery("SELECT p.products FROM Place p WHERE p.id = :Id", Product.class);
From Documentation :
<T> TypedQuery<T> createQuery(java.lang.String qlString,
java.lang.Class<T> resultClass)
Create an instance of TypedQuery for executing a Java Persistence
query language statement. The select list of the query must contain
only a single item, which must be assignable to the type specified by
the resultClass argument.
Parameters:
qlString - a Java Persistence query string
resultClass - the type of the query result
Edit :
You can try the following code.
Place place = entityManager.createQuery("SELECT p FROM Place p WHERE p.id = :Id", Place.class).getSingleResult();
List<Products> products = place.getProducts();
Also as a side-note, you are using JPA, but #Extension seems to be JDO specific annotation.
That class javadoc tells that it implements java.util.List, so it is a valid return type.
Remember that the specification says that you get a List as a return type, not a java.util.ArrayList, so any class that implements List is as valid as any other.
UPDATE:
Try:
SELECT pr FROM Place pl INNER JOIN pl.products pr WHERE pl.id = :Id

While calling SQL Server stored procedure from NHibernate can I pass list or custom data type as a parameter

I tested this with Oracle. It is working fine. Because there I have Package and defined Associative Array type and Stored Procedure in Package body.
Though there are no concept of packages in SQL Server. How to make this work in SQL Server?
Domain Object Start
[Serializable]
public class Employee
{
public virtual int EmployeeId
{
get;
set;
}
public virtual string EmployeePassword
{
get;
set;
}
public virtual string EmployeeName
{
get;
set;
}
public virtual int TeamAssociatedWith
{
get;
set;
}
public virtual string IsCaptain
{
get;
set;
}
public virtual int NumberOfMOM
{
get;
set;
}
public virtual int Balance
{
get;
set;
}
}
Mapping
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="DomainObject.Employee,DomainObject" table="Employee">
<id name="EmployeeId" column="EMP_ID" type="int" unsaved-value="0">
<generator class="native">
</generator>
</id>
<property name="EmployeePassword" column="EMP_PASSWORD" type="string"/>
<property name="EmployeeName" column="EMP_NAME" type="string"/>
<property name="TeamAssociatedWith" column="TEAM_ASSOCIATED_WITH" type="int"/>
<property name="IsCaptain" column="IS_CAPTAIN" type="string"/>
<property name="Balance" column="BALANCE" type="int"/>
<property name="NumberOfMOM" column="NO_OF_MOM" type="int"/>
</class>
</hibernate-mapping>
Stored procedure
CREATE PROCEDURE [dbo].[some_sp] #id IntTable READONLY
AS
SELECT EMP_ID,EMP_NAME,EMP_PASSWORD,
TEAM_ASSOCIATED_WITH,IS_CAPTAIN,NO_OF_MOM,BALANCE
FROM employee;
GO
ISQLQuery final = eventhistorysession.CreateSQLQuery("EXEC TestCustom #location = :id");
IQuery result = final.SetStructured("id", dt);
IList finalResult = result.List();
In SQL Server, stored procedures can have parameters of type table that can be used to mimic the Oracle Associative Array feature. In your situation, you'd be sending a "table" with a single row and multiple columns. There is a good example for NHibernate here in the accepted answer.

Is it possible to use Full Text Search (FTS) with LINQ?

I wonder if is possible to use FTS with LINQ using .NET Framework 3.5. I'm searching around the documentation that I didn't find anything useful yet.
Does anyone have any experience on this?
Yes. However you have to create SQL server function first and call that as by default LINQ will use a like.
This blog post which will explain the detail but this is the extract:
To get it working you need to create a table valued function that does
nothing more than a CONTAINSTABLE query based on the keywords you pass
in,
create function udf_sessionSearch
(#keywords nvarchar(4000))
returns table
as
return (select [SessionId],[rank]
from containstable(Session,(description,title),#keywords))
You then add this function to your LINQ 2 SQL model and he presto you
can now write queries like.
var sessList = from s in DB.Sessions
join fts in DB.udf_sessionSearch(SearchText)
on s.sessionId equals fts.SessionId
select s;
No. Full text search is not supported by LINQ To SQL.
That said, you can use a stored procedure that utilizes FTS and have the LINQ To SQL query pull data from that.
if you do not want to create joins and want to simplify your C# code, you can create SQL function and use it in "from" clause:
CREATE FUNCTION ad_Search
(
#keyword nvarchar(4000)
)
RETURNS TABLE
AS
RETURN
(
select * from Ad where
(CONTAINS(Description, #keyword) OR CONTAINS(Title, #keyword))
)
After updating your DBML, use it in linq:
string searchKeyword = "word and subword";
var result = from ad in context.ad_Search(searchKeyword)
select ad;
This will produce simple SQL like this:
SELECT [t0].ID, [t0].Title, [t0].Description
FROM [dbo].[ad_Search](#p0) AS [t0]
This is works in search by several columns as you can see from the ad_Search function implementation.
I don't believe so. You can use 'contains' on a field, but it only generates a LIKE query. If you want to use full text I would recommend using a stored proc to do the query then pass it back to LINQ
No, full text searching is something very specific to sql server (in which text is indexed by words, and queries hit this index versus traversing a character array). Linq does not support this, any .Contains() calls will hit the un-managed string functions but will not benefit from indexing.
I made a working prototype, for SQL Server's CONTAINS only and no wildcard columns. What it achieves is for you to use CONTAINS like ordinary LINQ functions:
var query = context.CreateObjectSet<MyFile>()
.Where(file => file.FileName.Contains("pdf")
&& FullTextFunctions.ContainsBinary(file.FileTable_Ref.file_stream, "Hello"));
You will need:
1.Function definitions in code and EDMX to support the CONTAINS keyword.
2.Rewrite EF SQL by EFProviderWrapperToolkit/EFTracingProvider, because CONTAINS is not a function and by default the generated SQL treats its result as bit.
BUT:
1.Contains is not really a function and you cannot select boolean results from it. It can only be used in conditions.
2.The SQL rewriting code below is likely to break if queries contain non-parameterized strings with special characters.
Source of my prototype
Function Definitions: (EDMX)
Under edmx:StorageModels/Schema
<Function Name="conTAINs" BuiltIn="true" IsComposable="true" ParameterTypeSemantics="AllowImplicitConversion" ReturnType="bit" Schema="dbo">
<Parameter Name="dataColumn" Type="varbinary" Mode="In" />
<Parameter Name="keywords" Type="nvarchar" Mode="In" />
</Function>
<Function Name="conTAInS" BuiltIn="true" IsComposable="true" ParameterTypeSemantics="AllowImplicitConversion" ReturnType="bit" Schema="dbo">
<Parameter Name="textColumn" Type="nvarchar" Mode="In" />
<Parameter Name="keywords" Type="nvarchar" Mode="In" />
</Function>
PS: the weird cases of chars are used to enable the same function with different parameter types (varbinary and nvarchar)
Function Definitions: (code)
using System.Data.Objects.DataClasses;
public static class FullTextFunctions
{
[EdmFunction("MyModel.Store", "conTAINs")]
public static bool ContainsBinary(byte[] dataColumn, string keywords)
{
throw new System.NotSupportedException("Direct calls are not supported.");
}
[EdmFunction("MyModel.Store", "conTAInS")]
public static bool ContainsString(string textColumn, string keywords)
{
throw new System.NotSupportedException("Direct calls are not supported.");
}
}
PS: "MyModel.Store" is as same as the value in edmx:StorageModels/Schema/#Namespace
Rewrite EF SQL: (by EFProviderWrapperToolkit)
using EFProviderWrapperToolkit;
using EFTracingProvider;
public class TracedMyDataContext : MyDataContext
{
public TracedMyDataContext()
: base(EntityConnectionWrapperUtils.CreateEntityConnectionWithWrappers(
"name=MyDataContext", "EFTracingProvider"))
{
var tracingConnection = (EFTracingConnection) ((EntityConnection) Connection).StoreConnection;
tracingConnection.CommandExecuting += TracedMyDataContext_CommandExecuting;
}
protected static void TracedMyDataContext_CommandExecuting(object sender, CommandExecutionEventArgs e)
{
e.Command.CommandText = FixFullTextContainsBinary(e.Command.CommandText);
e.Command.CommandText = FixFullTextContainsString(e.Command.CommandText);
}
private static string FixFullTextContainsBinary(string commandText, int startIndex = 0)
{
var patternBeg = "(conTAINs(";
var patternEnd = ")) = 1";
var exprBeg = commandText.IndexOf(patternBeg, startIndex, StringComparison.Ordinal);
if (exprBeg == -1)
return commandText;
var exprEnd = FindEnd(commandText, exprBeg + patternBeg.Length, ')');
if (commandText.Substring(exprEnd).StartsWith(patternEnd))
{
var newCommandText = commandText.Substring(0, exprEnd + 2) + commandText.Substring(exprEnd + patternEnd.Length);
return FixFullTextContainsBinary(newCommandText, exprEnd + 2);
}
return commandText;
}
private static string FixFullTextContainsString(string commandText, int startIndex = 0)
{
var patternBeg = "(conTAInS(";
var patternEnd = ")) = 1";
var exprBeg = commandText.IndexOf(patternBeg, startIndex, StringComparison.Ordinal);
if (exprBeg == -1)
return commandText;
var exprEnd = FindEnd(commandText, exprBeg + patternBeg.Length, ')');
if (exprEnd != -1 && commandText.Substring(exprEnd).StartsWith(patternEnd))
{
var newCommandText = commandText.Substring(0, exprEnd + 2) + commandText.Substring(exprEnd + patternEnd.Length);
return FixFullTextContainsString(newCommandText, exprEnd + 2);
}
return commandText;
}
private static int FindEnd(string commandText, int startIndex, char endChar)
{
// TODO: handle escape chars between parens/squares/quotes
var lvlParan = 0;
var lvlSquare = 0;
var lvlQuoteS = 0;
var lvlQuoteD = 0;
for (var i = startIndex; i < commandText.Length; i++)
{
var c = commandText[i];
if (c == endChar && lvlParan == 0 && lvlSquare == 0
&& (lvlQuoteS % 2) == 0 && (lvlQuoteD % 2) == 0)
return i;
switch (c)
{
case '(':
++lvlParan;
break;
case ')':
--lvlParan;
break;
case '[':
++lvlSquare;
break;
case ']':
--lvlSquare;
break;
case '\'':
++lvlQuoteS;
break;
case '"':
++lvlQuoteD;
break;
}
}
return -1;
}
}
Enable EFProviderWrapperToolkit:
If you get it by nuget, it should add these lines into your app.config or web.config:
<system.data>
<DbProviderFactories>
<add name="EFTracingProvider" invariant="EFTracingProvider" description="Tracing Provider Wrapper" type="EFTracingProvider.EFTracingProviderFactory, EFTracingProvider, Version=1.0.0.0, Culture=neutral, PublicKeyToken=def642f226e0e59b" />
<add name="EFProviderWrapper" invariant="EFProviderWrapper" description="Generic Provider Wrapper" type="EFProviderWrapperToolkit.EFProviderWrapperFactory, EFProviderWrapperToolkit, Version=1.0.0.0, Culture=neutral, PublicKeyToken=def642f226e0e59b" />
</DbProviderFactories>
</system.data>

Resources