ahmetb / orman Goto Github PK
View Code? Open in Web Editor NEWlightweight and minimalist ORM for Java/Android. works with SQLite & MySQL. (not actively maintained)
License: Other
lightweight and minimalist ORM for Java/Android. works with SQLite & MySQL. (not actively maintained)
License: Other
Hi.
I'm trying to create a one-to-many relationship just like in the wiki example.
These are my class:
@Entity
public class CadenaDBO extends Model<CadenaDBO> {
@PrimaryKey(autoIncrement=true)
public long id;
private String uid;
private String medioRef;
private String title;
private String permalink;
@OneToMany(toType = ProgramaDBO.class, onField = "channel")
public EntityList<CadenaDBO, ProgramaDBO> programas = new EntityList(CadenaDBO.class, ProgramaDBO.class, this);
.
.
}
@Entity
public class ProgramaDBO extends Model<ProgramaDBO> {
@PrimaryKey(autoIncrement=true)
public long id;
private String uid;
private String name;
private String permalink;
private String language;
@ManyToOne
private CadenaDBO channel;
}
Like in the wiki example but when I try to insert an element, first in CadenaDBO I'm getting a error column uid not unique.
I'm creating an Object and then I execute objectCadena.insert()
I can see the error in DDMS and the query is : INSTERT INTO cadena_dbo (permalink, uid, title, medioref) VALUES .....
Where is the long id
column with autoincrement???
Currently we don't have any distributable builds. However when we have, we should distribute code under an appropriate license so that developers can use it even in their commercial applications.
Any license suggestions for the framework? Examples from other frameworks?
Uncaught handler: thread main exiting due to uncaught exception
java.lang.NullPointerException
at org.orman.mapper.F.formatField(F.java:38)
at org.orman.mapper.F.formatField(F.java:28)
at org.orman.mapper.C.eq(C.java:18)
at org.orman.mapper.EntityList.refreshList(EntityList.java:115)
at org.orman.mapper.EntityList.lazyLoadIfNeeded(EntityList.java:77)
at org.orman.mapper.EntityList.add(EntityList.java:128)
at com.package.name.ClassName$2.onClick(ClassName.java:126)
at com.android.internal.app.AlertController$ButtonHandler.handleMessage(AlertController.java:158)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:123)
at android.app.ActivityThread.main(ActivityThread.java:4363)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
at dalvik.system.NativeStart.main(Native Method)
The latest nightly build from the downloads section and the source code has the same problem, I found that the fieldName contains the generatedFieldName instead of the fieldName which returns null for Field always. I've used a temporary workaround (F.java) which fixed this issue.
public static Field getField(Entity e, String fieldName) {
for (Field f : e.getFields())
if (f.getOriginalName().equals(fieldName) ||
f.getGeneratedName().equals(fieldName))
return f;
return null;
}
when use QueryBuilder Max and Min fuction call sum sql funcion
I need to store a string like this :
<![CDATA[<div id='new'><div class="chapeaux"><ul>
And it's giving me Bad format exception in the insert query because of the ' and the %
How can I avoid this?
If we reference an object from itself (e.g @Entity class A { @OneToOne private A parent; }
entity dependency graph inspector thinks that it is a different entity and this creates a cycle (short-circuit) in the dependency graph therefore throws UnsolvableDependencyOrderException
and of course @OneToOne
does not solve this.
I will be fixing. (@almozavr reported this)
Can't reopen issue #17, so have to create a new one.
org.orman.mapper.ReverseMapping
is broken as its method map()
causes ClassCastException
when trying to cast String
to Integer
: fieldValue = enumConstant[(Integer) fieldValue];
.
The whole enum processing should be moved to smartCasting()
method and use new Integer(value.toString())
for enums.
Enum fields can be used as persistent fields on the database. We can store them as their (integer) order values or if they have a special constructor values, we should still user their order because constructor can be multi-variable.
Implement reverse mapping support as well.
A methodless DatabaseSettings
interface (under org.orman.dbms
) can be created to classify SQLiteSettingsImpl
, MySQLiteSettings
classes in an OOP way.
Currently, SQLite uses SQLiteSettingsImpl
but SQLiteAndroid
does not. They both can share this interface.
SQLiteSettingsImpl
to SQLiteSettings
.org.orman.sqlite.generic
package.DatabaseSettings
interface.When I execute update on model instance my application throws following exception:
java.lang.NullPointerException at org.orman.mapper.Model.prepareUpdateQuery(Model.java:197)
at org.orman.mapper.Model.update(Model.java:162)
In my entity I use text field with as primary key which I manually fill before storing into database. Since method prepareUpdateQuery requires autoIncrement field it fails with NPE.
@entity(table = "sui")
public class SUI extends Model {
@PrimaryKey
private String id;
...
}
In my opinion prepareUpdateQuery should check against @PrimaryKey annotation instead of autoincrement value.
An idea to implement in the future,
The framework may scan the current project for @Entity
-annotated classes without registering an explicit package name. Issues to consider:
.start()
.)There is no logging adapter for java.util.logging
utility right now. It should be implemented if necessary.
We might consider supporting slf4j in the future http://www.slf4j.org/ It is also a similar Facade for many logging libraries like our ILogger
.
Example scenario below
@Entity class ToDo { boolean done; String text; }
Logs:
521 [TRACE] Executing: CREATE TABLE to_do (text TEXT, done INTEGER, id INTEGER PRIMARY KEY AUTOINCREMENT)
523 [TRACE] Executing: DROP INDEX IF EXISTS to_do_index
523 [INFO] DDL constructed successfully.
579 [TRACE] Executing: INSERT INTO to_do (text, done) VALUES ('dishes', false)
Exception in thread "main" 580 [ERROR] Query execution error: SQLite error:com.almworks.sqlite4java.SQLiteException: [1] DB[1] exec() no such column: false
org.orman.dbms.exception.QueryExecutionException: Query execution error: SQLite error:com.almworks.sqlite4java.SQLiteException: [1] DB[1] exec() no such column: false
at org.orman.dbms.sqlite.QueryExecutionContainerImpl.throwError(QueryExecutionContainerImpl.java:38)
at org.orman.dbms.sqlite.QueryExecutionContainerImpl.executeOnly(QueryExecutionContainerImpl.java:114)
at org.orman.mapper.Model.insert(Model.java:86)
at demo10todo.Main.main(Main.java:23)
Because SQLite does not have boolean
but can store 0
and 1
in int
field and we are serializing boolean variables using Boolean.toString()
method in org.orman.sql.util.Serializer.java
.
We should investigate that using 0
instead of false
and 1
instead of true
will work in MySQL and also compatible with generic SQL implementations.
In order to upgrade my schema I've created my own SQLiteOpenHelper which does the upgrades at startup. In my last update, something bad happened: Users are reporting this error...
Caused by: android.database.sqlite.SQLiteException: Can't downgrade database from version 35 to 33
at android.database.sqlite.SQLiteOpenHelper.onDowngrade(SQLiteOpenHelper.java:307)
at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:168)
at org.orman.dbms.sqliteandroid.SQLiteAndroid.(SQLiteAndroid.java:39)
[...]
And indeed, my db version went from 33 to 34. I saw in the orman code the following line:
public class SQLiteAndroid extends SQLiteOpenHelper implements Database {
private static final int SQLITE_VERSION = 33; //TODO read from somewhere else ASAP
... and I'm suspecting that this could be causing the problem.
Right now I'm a bit at a loss here, do you see a possibility for a quick fix?
We might provide a way for thread-safe query executions in Android usage with SQLiteHelper methods:
http://stackoverflow.com/questions/6675240/is-sqlite-database-instance-thread-safe/6675272
If two or more fields or entities are mapped to the same physical name (in a case-[in]sensitive manner (create a case sensitivity option in MappingConfiguration)), an exception must be thrown to not to defer error to the DBMS. This should be done during name and type binding checks in MappingSession.
In QueryType
s, we define e.g.
SELECT {SELECT_COLUMN_LIST} FROM {TABLE_LIST} {JOIN}{WHERE}{GROUP_BY}{HAVING}{ORDER_BY}{LIMIT}
however that can be exploited if some query values do also include these {...}
templates and may cause complicated errors. Values manually binded to SQL should be escaped for {
and }
then must be unescaped.
People do not necessarily have to install log4j
to log framework events to a file. A simple file appender is required as implemented in log4j
. Should be implemented in a thread-safe way using (if necessary) low level java.io API.
Currently almost all classes (and many of their methods) are declared as public
. Some of them can be restricted to be accessed only from enclosing package. This will maintain least-privilege for any accessor class and won't let users of the framework get confused about framework internals.
When there is:
@entity
public class Message extends Model{
@PrimaryKey(autoIncrement = true)
public int rowId;
@Index
public int id;
public int title;
public int text;
@OneToOne
public Message parentMessage;
}
error occurs saying column parent_message is not unique
It's a some kind of restriction, but! One should feel free to use unique indexes even in this situation.
P.S. everything works if I use set @Index as not unique.
Hi.
I'm forcing with strange update() problem. I have a quite complicated entity which has ManyToMany (or OneToMany) and a problem appears when I try to update entity which is already in DB. So even if I fetch entity from DB and then update the orman fails to do it giving following exception:
09-19 09:26:19.830: ERROR/AndroidRuntime(318): Caused by: org.orman.dbms.exception.QueryExecutionException:
Query execution error: SQLiteAndroid error:android.database.sqlite.SQLiteException:
near ".": syntax error: UPDATE stream SET message=1, messages_using_it=(com.sample.project.model.Message@f879683e),
title='New discussion', users=(com.sample.project.model.User@f6fdfd03) WHERE row_id = 1;
09-19 09:26:19.830: ERROR/AndroidRuntime(318): at org.orman.dbms.sqliteandroid.QueryExecutionContainerImpl.throwError(QueryExecutionContainerImpl.java:30)
09-19 09:26:19.830: ERROR/AndroidRuntime(318): at org.orman.dbms.sqliteandroid.QueryExecutionContainerImpl.executeOnly(QueryExecutionContainerImpl.java:41)
09-19 09:26:19.830: ERROR/AndroidRuntime(318): at org.orman.mapper.Model.update(Model.java:164)
Every request to db gives me following errors:
Am I doing something wrong or something wrong with framework? Must admit, that transactions work anyway, but I get all this errors and app crashes.
Using criteria binding fields during SQL Query Building with QueryBuilder
check for vulnerabilities of DBMSes to SQL injection attacks.
Currently it seems there are problems in SQLite, and most probably in MySQL.
QueryExecutionContainerImpl.java
conn = DriverManager.getConnection(
"jdbc:mysql://" + this.settings.getHost() + ":"
+ this.settings.getPort() + "/"
+ this.settings.getDatabase(), props);
there is no dufault characterEncoding ,and we can't do any customize?
Not all DBMSes follow SQL standards. Some keywords differ in specific dbms systems.
e.g. PRIMARY KEY, AUTO INCREMENT may differ however many of db systems follow standards in FOREIGN KEY.
Extract hard-wired keywords and bind them to SQLGrammarProvider
implementation of databases.
@Entity
classes may have fields which are not stored on the database (to use them on runtime). That can be supported using Java keyword volatile
on these fields.
Currently this option is not working, investigate.
I start the Mapping Session in my Activity's onCreate method. Once I back out of the application and restart it once again I get the following exception:
11-27 17:55:53.448: E/AndroidRuntime(754): Caused by: org.orman.mapper.exception.MappingSessionAlreadyStartedException: Mapping session has already been started. Do not use start method more than once.
The app then crashes, but the next time I open the app, it works fine.
public static void initOrmanMappingSession(Class<?>[] entityClasses, Database database) {
System.gc();
MappingSession.getConfiguration().setCreationPolicy(SchemaCreationPolicy.CREATE_IF_NOT_EXISTS);
MappingSession.registerDatabase(database);
for(Class<?> clazz : entityClasses) {
MappingSession.registerEntity(clazz);
}
MappingSession.startSafe();
}
Please override toString() method because by default it is returning enum name that contains _ charater and leads to syntax error in query execution.
Create Index queries must provide option to use btree or hash index via annotation.
(separating this from issue from #29 comment #29 (comment))
When we log executed SQL statements using Log.trace
, it uses String.format(message, [params...])
method of Java API.
If the SQL itself has %
characters somewhere (like in string literals or wildcard in LIKE
clause) it throws java.util. MissingFormatArgumentException
. In this case `%'% causes it.
Assigning to myself. (@almozavr reported this bug)
when work with ModelQuery not find sql aggregate functions such as sum,max,min and others
please add sql aggregate functions to ModelQuery .
Foreign key cascading options should be implemented in OneToMany
, ManyToMany
and ManyToOne
cardinality annotations and in language grammars along with enumeration templates.
I'm trying to create a column which has the following constraints:
UNIQUE
valuesNULL
values.PRIMARY KEY
column.Note that SQLite allows NULL
values in columns designated as UNIQUE
- Reference
Since Orman uses the @Index
annotation do designate UNIQUE
-ness, I tried the following:
@Entity
public class Node extends Model<Node> {
@PrimaryKey(autoIncrement = true)
@Column(name = "_id")
private int id;
@Index(unique=true, name="uname")
private String uniqueName;
//...
}
However, Orman generates the following DDL for this:
Executing: CREATE TABLE IF NOT EXISTS node (uname TEXT NOT NULL, _id INTEGER PRIMARY KEY AUTOINCREMENT)
Expected DDL is the following:
CREATE TABLE IF NOT EXISTS node (uname TEXT UNIQUE, _id INTEGER PRIMARY KEY AUTOINCREMENT)
So, how do I set a column as UNIQUE but NULLable in SQLite (Android)?
Currently, creation of tables are ordered by entities with less foreign keys first principle and during deletion of tables the policy is delete entities with more foreign keys first in order not to break foreign key constraints. This is very poor.
This policy will not always work and implemented very earlier just to get things work – a nasty hack.
Consider the following tables:
Table A --> FK: A.X references C.X
Table B --> FK: B.Y references A.X
Table C
Table D--> FK: D.Z references C.Z &
D.W references C.W.
With our algorithm the possible creation orders (first to last):
however if the first schedule is chosen, it won't work because when attempted to create B we say
CREATE TABLE B ...(..., FOREIGN KEY B.Y REFERENCES A.X)
however A does not exist, yet.
We need to implement a dependency tree plugin (which is constructed just before calling createScheme()
in MappingSession.start()
. It will help us have safe way to create and drop tables according to SchemeCreationPolicy
.
The enough information can be obtained from
MappingSession.scheme.getEntities()
-->List<Entity>
-->e.getFields()
-->Field
--> (f.isForeignKey()
, f.getClazz()`).
If an entity e.g. Message contains ref. entity Message as a field there is a loop exception.
@entity
public class Message extends Model{
@PrimaryKey(autoIncrement = true)
public int rowId;
public int title;
public int text;
public Message parentMessage;
public Message{
}
}
I tried to set @OneToOne(load = LoadingPolicy.LAZY)
for parentMessage
but it doesn't help at all.
We need a schema inspector that can query databases and retrieve schema information of database (tables, columns etc.) so that in some modes, we can prevent database throwing exceptions such as "database already exists" or "column not found" etc. SQLite and MySQL provides that information.
We can design an interface and implement it in every dbms package. It can store Table
and DataField
(reuse from org.orman.sql
) so that we can compare their existence by name (case insensitive) and throw exceptions before DBMS throws them and user could not understand them easily.
That inspector interface can implement tableExists(name)
, columnExists(tableName, colName)
methods. Maybe we can check for indexes like indexExists(tableName, indexName)
.
I found orman very simple to understand and easy to maintain. It's usage is really awesome. But because of restriction to use auto-increment field I can't use it in my project and that's way:
I appreciate your work (framework is really cool comparing to db4o, ormlite etc.) and hope one day my issue would be accepted. Thanks.
Bulk insert method is not documented and it is especially an important feature for this framework since we aim data-embedded shipping products.
Therefore a Wiki page describing usage of bulk insert would be helpful.
I don't know if this is the right place for this...
I'm trying to create a simple android project using orman but can't get my entities mapped.
I have all my entities under the "br.com.jera.shoplist.model" package and when i try to start the session i get this error:
org.orman.mapper.exception.AnnotatedClassNotFoundInPackageException: Could not find any entity marked class in "br.com.jera.shoplist.model"
Before anybody asks, all my entities have the @entity annotation.
I'm using this in my activty to start the session:
//database
Database db = new SQLiteAndroid(getApplicationContext(), "shoplist.db");
MappingSession.getConfiguration().setCreationPolicy(SchemaCreationPolicy.CREATE);
MappingSession.registerPackage("br.com.jera.shoplist.model");
MappingSession.registerDatabase(db);
MappingSession.start();
Any idea? am I missing something?
hi,I map the data to mysql, but it lost the time, and the time just show 00:00:00,
so, I think may it's a bug? and how did we map time to mysql?
At some points we Log.error
the exceptions we have thrown. However, should we log all of them, or not? This is an important design choice.
IMHO, to provide good maintainability, we should log all exceptions, because the client program may catch it, however it is already thrown by the framework and should appear in "framework logs".
There are about ~53 exceptions in the code thrown like :
throw new [...]
We should have something like this for all exceptions:
Exception e = new [...]
Log.err(e.getMessage());
throw e;
Let's discuss.
We need a build mechanism that can build and package project into a JAR file. Maybe we can think about using jarjar
for bundling connector/adapter dependencies for targeted builds.
For instance, core
build should not contain a connector in JAR package.
mysql
build should contain lib/mysql-connector-java-*.jar
sqlite-unix
build should contain lib/sqlite4java.jar
and lib/*.so
+lib/*.jnilib
binaries.
sqlite-windows
build should contain lib/sqlite4java.jar
and sqlite4java-win32-*.dll
dynamic linkers.
etc.
Build tool can be Maven, Rake, sbt, Ant or anything that makes sense, easy to maintain and not outdated.
Build should be single step! See Joel's test.
Currently all exceptions extend RuntimeException. We need a hierarchy for exceptions.
For instance:
some of them already under org.orman.datasource.exception. Move appropriate ones to org.orman.exception [new] package.
Hi.
I have some class for example class A , and class B which extends A. I can't store both in DB because If I want that classes to be an Entity, they need to extend Model< A> and Model< B>.
Is there any solution?
I have entity with double datatype field. i insert number such as 17507321 and inserted correct but when retrieve value form database convert to 17507300
Since we are aiming easy integration and use, especially for Java desktop programs shipping, we can not setup a MySQL or a similar daemon-running DBMS.
For that we planned to write adapters for SQLite however there is no pure Java adapter for that and even sqlite4java requires native *.dll, *.so, *.jnilib
binaries. Maybe we can embed them into sqlite-build of ORMAN distribution however that would be inefficient and large anyway.
I found out that H2 db might be useful. However it is about ~1 mb and has lots of features. We're looking for a very very simple and small SQL-interpreting pure Java database.
Just an idea to improve usability of framework.
We should delay establishing connections to DBMSes (if necessary) until MappingSession.start()
since it is a blocking task and should not run upon initialization of adapter (which is an org.orman.datasource.Database
implementation).
Currently framework has no date type supports. Databases have different input and query result formats for date & date-time types.
Plan is to support only datetime
types (which is java.sql.Date
) and let every dbms have its own DateFormatter
(or SimpleDataFormat
) on both forward mapping and reverse mapping.
Tests should also be done.
Hi.
I'm actually using orman on android and I think it's a really convenient orm.
Actually, I got a serious issue. I found a way to fix it temporary but It's not as clean as I would want.
Let me explain:
I got 1 class named Noeud (node) and 1 classe named Equipement (equipment).
Noeud has two ManyToOne relationships. One with itself (on field "parent") and one to Equipement (on field "localisation").
My problem is: when I try to access equipment (by using node.getEquipements()), I got the following error:
org.orman.mapper.exception.FieldNotFoundException: Could not find property (field) parent
in Equipement.
I checked, double-checked, triple-checked my ManyToOne declarations (code below) but problem is still here).
I have the impression that all ManyToOne associations of one class are sharing their foreign key names.
I solved the problem by renaming "localisation" field on Equipement to "parent" and it seems to work but it could be a problem if I was right about the cause.
class Noeud extends Model<Noeud> {
@OneToMany(onField = Equipement.PROP_LOCALISATION, toType = Equipement.class, load = LoadingPolicy.LAZY)
private EntityList<Noeud, Equipement> equipements = new EntityList<Noeud, Equipement>(Noeud.class, Equipement.class, this);
@OneToMany(onField = "parent", toType = Noeud.class, load = LoadingPolicy.LAZY)
private EntityList<Noeud, Noeud> children = new EntityList<Noeud, Noeud>(Noeud.class, Noeud.class, this);
}
class Equipement extends Model<Equipement> {
public static final String PROP_LOCALISATION = "localisation"; //actually renamed to "parent"
@ManyToOne(load = LoadingPolicy.LAZY)
private Noeud localisation; //also renamed to "parent"
}
Do that sounds familiar to you? Did I miss something in documentation or in my code?
Best regards.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.