agrosner / dbflow Goto Github PK
View Code? Open in Web Editor NEWA blazing fast, powerful, and very simple ORM android database library that writes database code for you.
License: MIT License
A blazing fast, powerful, and very simple ORM android database library that writes database code for you.
License: MIT License
I having a problem using a ModelView. I have traced the problem to these lines in the convertToModel method in SqlUtils:
Class persistentClass = (Class) ((ParameterizedType) table.getGenericSuperclass()).getActualTypeArguments()[0];
if (persistentClass.isAssignableFrom(BaseModelView.class)) {
model = (ModelClass) FlowManager.getModelViewAdapter((Class<? extends BaseModelView<? extends Model>>) table).loadFromCursor(cursor);
}
The problem is that persistentClass
gets assigned to the class of the real table rather than the class of the view, but then is checked to see if it extends BaseModelView. As a result, model
always returns as null. Shouldn't you instead be checking if table
extends this class?
Modify the existing ModelAdapter
to not use ContentValues
for insertion, rather use SQLiteStatement
to exponentially speed up bulk insertions
To remove limitation of public/package private fields, we can add this feature to look for a getter and setter for a Model field if its private.
Target Release: 1.5.0 or later
Usually the DB file is stored under /data/data/com.yourpackage.yourapp/databases/yourdb
I'm using DBFlow and I need to debug the contents of my Database and I don't find it anywhere. Someone can help?
Cheers, and sorry for opening an issue just for this.
The goal of this issue is to address:
ModelView
This may be more of a question for the Robolectric team, but I'll post it here first.
I have a very simple Dao class:
public class ReviewsDao {
public ReviewsDao() {
}
public synchronized void saveList(List<Review> reviews){
TransactionManager.getInstance().saveOnSaveQueue(reviews);
}
public Review get(String key){
return Select.byId(Review.class, key);
}
}
And a very simple Unit test:
@RunWith(RobojavaTestRunner.class)
public class ReviewsDaoTest {
ReviewsDao dao;
@Test
public void testSaveListAndGet() throws Exception {
dao = new ReviewsDao();
List<Review> reviews = new ArrayList<>(10);
for(int i=0; i<10; i++){
Review review = new Review();
review.id = "id_" + i;
review.title = "Review " + i;
reviews.add(review);
}
dao.saveList(reviews);
Thread.sleep(100);
for(int i=0; i<10; i++) {
Review review = dao.get("id_" + i);
assertThat(review).isNotNull();
assertThat(review.title).isEqualTo("Review " + i);
}
}
}
When I run this unit test alone, it completes without error. However, when I run it as part of an entire test suite, I get the following errors:
WARNING: [sqlite] [ROLLBACK;]DB[1][C]: exception when clearing
com.almworks.sqlite4java.SQLiteException: [1] DB[1] reset [cannot rollback - no transaction is active]
at com.almworks.sqlite4java.SQLiteConnection.throwResult(SQLiteConnection.java:1309)
at com.almworks.sqlite4java.SQLiteConnection.throwResult(SQLiteConnection.java:1282)
at com.almworks.sqlite4java.SQLiteConnection.cacheStatementHandle(SQLiteConnection.java:1211)
at com.almworks.sqlite4java.SQLiteConnection.access$900(SQLiteConnection.java:54)
at com.almworks.sqlite4java.SQLiteConnection$CachedController.dispose(SQLiteConnection.java:1606)
at com.almworks.sqlite4java.SQLiteStatement.dispose(SQLiteStatement.java:187)
at org.robolectric.shadows.ShadowSQLiteConnection$Connections$4.call(ShadowSQLiteConnection.java:394)
at org.robolectric.shadows.ShadowSQLiteConnection$Connections$6.call(ShadowSQLiteConnection.java:422)
at org.robolectric.shadows.ShadowSQLiteConnection$Connections$6.call(ShadowSQLiteConnection.java:416)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
Exception in thread "TransactionManager" java.lang.RuntimeException: android.database.sqlite.SQLiteException: Cannot execute, base error code: 1
at com.raizlabs.android.dbflow.runtime.DBTransactionQueue.run(DBTransactionQueue.java:77)
Caused by: android.database.sqlite.SQLiteException: Cannot execute, base error code: 1
at org.robolectric.shadows.ShadowSQLiteConnection.rethrow(ShadowSQLiteConnection.java:48)
at org.robolectric.shadows.ShadowSQLiteConnection.access$500(ShadowSQLiteConnection.java:26)
at org.robolectric.shadows.ShadowSQLiteConnection$Connections.execute(ShadowSQLiteConnection.java:436)
at org.robolectric.shadows.ShadowSQLiteConnection.nativeExecute(ShadowSQLiteConnection.java:112)
at android.database.sqlite.SQLiteConnection.nativeExecute(SQLiteConnection.java)
at android.database.sqlite.SQLiteConnection.execute(SQLiteConnection.java:555)
at android.database.sqlite.SQLiteSession.endTransactionUnchecked(SQLiteSession.java:439)
at android.database.sqlite.SQLiteSession.endTransaction(SQLiteSession.java:401)
at android.database.sqlite.SQLiteDatabase.endTransaction(SQLiteDatabase.java:522)
at com.raizlabs.android.dbflow.runtime.TransactionManager.transact(TransactionManager.java:119)
at com.raizlabs.android.dbflow.runtime.transaction.process.ProcessModelHelper.process(ProcessModelHelper.java:26)
at com.raizlabs.android.dbflow.runtime.transaction.process.ProcessModelTransaction.onExecute(ProcessModelTransaction.java:34)
at com.raizlabs.android.dbflow.runtime.transaction.process.ProcessModelTransaction.onExecute(ProcessModelTransaction.java:12)
at com.raizlabs.android.dbflow.runtime.DBTransactionQueue.run(DBTransactionQueue.java:63)
Caused by: com.almworks.sqlite4java.SQLiteException: [1] DB[1] step() [ROLLBACK;]DB[1][C] [cannot rollback - no transaction is active]
at com.almworks.sqlite4java.SQLiteConnection.throwResult(SQLiteConnection.java:1309)
at com.almworks.sqlite4java.SQLiteConnection$BaseController.throwResult(SQLiteConnection.java:1562)
at com.almworks.sqlite4java.SQLiteStatement.stepResult(SQLiteStatement.java:1231)
at com.almworks.sqlite4java.SQLiteStatement.step(SQLiteStatement.java:302)
at com.almworks.sqlite4java.SQLiteStatement.stepThrough(SQLiteStatement.java:316)
at org.robolectric.shadows.ShadowSQLiteConnection$4.call(ShadowSQLiteConnection.java:116)
at org.robolectric.shadows.ShadowSQLiteConnection$Connections$6.call(ShadowSQLiteConnection.java:422)
at org.robolectric.shadows.ShadowSQLiteConnection$Connections$6.call(ShadowSQLiteConnection.java:416)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
Any ideas of what I can do, perhaps at @Before
in the unit test to prevent this problem?
Currently in ConditionQueryBuilder
, if you append the same column between two different conditions, such as:
productName = 'plastic' OR productName = 'bags'
in ConditionQueryBuilder
, only the
productName = 'bags'
will end up running as the query.
The current query builder used for creating the tables is not very customizable. For example, for any String field DBFlow creates a TEXT db field(most of the times a varchar field is what we want to end up creating), default values (like CURRENT_TIMESTAMP) or unicity constraints on more than one field cannot be added, etc.
This can be somehow avoided if inside a migration we drop then recreate(or alter) the table using a raw sql query, but this approach is far from being ideal.
For example, for this class
@Table(value = Example.TABLE_NAME)
public static class Example{
public static final String TABLE_NAME = "example_table";
public interface Columns {
public static final String ID = "song_id";
public static final String NAME = "name";
public static final String CREATED_AT = "created_at";
public static final String POSITION = "position";
}
@Column(columnType = Column.PRIMARY_KEY, name = Columns.ID, onUniqueConflict = ConflictAction.REPLACE, notNull = true)
public int id;
@Column(name = Columns.POSITION, unique = true, onUniqueConflict = ConflictAction.REPLACE, notNull = true)
public Integer position;
@Column(name = Columns.NAME)
public String name;
@Column(name = Columns.CREATED_AT, notNull = true)
public Date createdAt;
}
this migration needs to run right after the default table is created
DROP TABLE IF EXISTS example_table;
CREATE TABLE example_table(
id INTEGER,
position INTEGER not null default 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
PRIMARY KEY(id),
unique(position)
);
It would be great if you could add compiler check when using SQL keywords in table model.
I had issue with model defined like this:
`@Table
public class MyModel extends BaseModel {
@Column(columnType = Column.PRIMARY_KEY_AUTO_INCREMENT)
public int primary;
@Column
public int id;
//... other colums
}`
It took me awhile to realize what was my mistake.
It would be great when compiler could detect this error and show descriptive message.
Left join between 2 tables:
final List<ProductRow> rows = new Select()
.from(ProductRow.class)
.join(PriceRecordRow.class, Join.JoinType.LEFT)
.using(ProductRow$Table.ID)
.queryList();
Returns a List of ProductRows, 2 fields of those items are not correctly initialised with values
(amount & unit fields not correctly initialised, tried both String as int representation).
Without a Join:
final List<ProductRow> rows = new Select()
.from(ProductRow.class)
.queryList();
Returns a List of ProductRows, all fields are correctly initialised with values.
I am a noob to android development but I am an experienced developer. It would really help me if you guys can make a "Getting Started" screencast for DBFlow using a simple android app. Coz for a simple reason I feel getting started screencasts are way faster than text based documentation.
Thanks a lot.
Why not compare DBFlow with Ollie?
ActiveAndroid is really old. Ollie is the improved follower.
thank you for great ormapper.
I want to use ForeignKeyReference.
@Table
public class Employee extends BaseModel {
//columns
@Column(columnType = Column.PRIMARY_KEY)
public Integer id;
@Column
public Integer divisionId;
//one to one relation.
@Column(columnType = Column.FOREIGN_KEY,
references = {@ForeignKeyReference(columnName = "divisionId" , columnType = Integer.class , foreignColumnName = "divisionId")})
public Division division;
//constructer
public Employee(){};
}
build error on Employee$Adapter.java
cause : Variable 'indexdivisionId' is already defined in the scope
@Override
public Employee loadFromCursor(Cursor cursor) {
Employee model = new Employee();
int indexid = cursor.getColumnIndex("id");
if (indexid != -1) {
model.id = cursor.getInt(indexid);
}
int indexdivisionId = cursor.getColumnIndex("divisionId");
if (indexdivisionId != -1) {
model.divisionId = cursor.getInt(indexdivisionId);
}
// Begin Loading division Model Foreign Key
int indexdivisionId = cursor.getColumnIndex("divisionId");////// this code is error
if ( indexdivisionId != -1 && !cursor.isNull(indexdivisionId)) {
model.division = new Select().from(jp.fores.dbflowtest.db.model.Division.class).where().and(Condition.column(jp.fores.dbflowtest.db.model.Division$Table.DIVISIONID).is(cursor.getInt(indexdivisionId))).querySingle();
}
// End
return model;
}
Sincerely
I have 2 models with a One-to-Many relationship, like below:
@Table
public class Dashboard extends BaseModel {
...
List<Chart> charts;
}
@Table
public class Chart extends BaseModel {
...
@Column(columnType = Column.FOREIGN_KEY, references = {@ForeignKeyReference(columnName = "dashboard_id", columnType = int.class, foreignColumnName = "id")})
Dashboard dashboard;
}
After creating a list of dashboards with Charts, I'm saving them on a transaction with TransactionManager.getInstance().save(ProcessModelInfo.withModels(dashboards))
my dashboards are saved but the charts inside are not. Am I missing something? Do I need to iterate through all dashboards and save charts in a similiar transaction?
Firstly amazing work. I would like to know if with the where method and using Condition if it possible to use wildcards? I looked around but couldn't seem to find anything on it.
An example of the query I am looking to resolve is:
SELECT * FROM myTable WHERE Name LIKE '%Doe%';
Model
class and return a list of those. IModel
class defined as @Join
to represent the JOIN statement.JOIN
statementsI put my database into app/src/main/assets.
I named it AppDatabase.
I have this class:
@database(name = AppDatabase.NAME, version = AppDatabase.VERSION, foreignKeysSupported = true)
public class AppDatabase {
public static final String NAME = "AppDatabase";
public static final int VERSION = 1;
}
And when I start my app, and run select command (new Select().from(Additive.class).where(Condition.column("Code").is(code)).querySingle();), file not found exception is thown and new empty database is created. Do I something wrong?
com.raizlabs.android.dbflow.sql.language.Join#as
returns the generic type Join
(without the type variables ModelClass
and FromClass
) which leads to IDE warnings.
In order to fix this problem the signature of the method needs to be changed from this
public Join as(String alias)
to this
public Join<ModelClass, FromClass> as(String alias)
I tried to save List<String>
, like this
@Table
@ContainerAdapter
public class AModel extends BaseModel {
...
@Column
List<String> strings;
}
@com.grosner.dbflow.annotation.TypeConverter
public class StringListConverter extends TypeConverter<String, List<String>> {
@Override
public String getDBValue(List<String> model) {
return GSON.toJson(model);
}
@Override
public List<String> getModelValue(String data) {
return GSON.fromJson(data, new TypeToken<List<String>>() {{
}}.getType());
}
}
But NPE occurred when I run ./gradlew assembleDebug
Please tell me if you know about that.
Stacktrace is here.
:app:compileDebugJava FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':app:compileDebugJava'.
> java.lang.NullPointerException
* Try:
Run with --info or --debug option to get more log output.
* Exception is:
org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':app:compileDebugJava'.
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:69)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:46)
at org.gradle.api.internal.tasks.execution.PostExecutionAnalysisTaskExecuter.execute(PostExecutionAnalysisTaskExecuter.java:35)
at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:64)
at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:58)
at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:42)
at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:52)
at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:53)
at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43)
at org.gradle.api.internal.AbstractTask.executeWithoutThrowingTaskFailure(AbstractTask.java:305)
at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.executeTask(AbstractTaskPlanExecutor.java:79)
at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.processTask(AbstractTaskPlanExecutor.java:63)
at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.run(AbstractTaskPlanExecutor.java:51)
at org.gradle.internal.concurrent.DefaultExecutorFactory$StoppableExecutorImpl$1.run(DefaultExecutorFactory.java:64)
Caused by: java.lang.RuntimeException: java.lang.NullPointerException
at com.sun.tools.javac.main.Main.compile(Main.java:553)
at com.sun.tools.javac.api.JavacTaskImpl.doCall(JavacTaskImpl.java:129)
at com.sun.tools.javac.api.JavacTaskImpl.call(JavacTaskImpl.java:138)
at org.gradle.api.internal.tasks.compile.jdk6.Jdk6JavaCompiler.execute(Jdk6JavaCompiler.java:45)
at org.gradle.api.internal.tasks.compile.jdk6.Jdk6JavaCompiler.execute(Jdk6JavaCompiler.java:38)
at org.gradle.api.internal.tasks.compile.NormalizingJavaCompiler.delegateAndHandleErrors(NormalizingJavaCompiler.java:97)
at org.gradle.api.internal.tasks.compile.NormalizingJavaCompiler.execute(NormalizingJavaCompiler.java:50)
at org.gradle.api.internal.tasks.compile.NormalizingJavaCompiler.execute(NormalizingJavaCompiler.java:36)
at org.gradle.api.internal.tasks.compile.CleaningJavaCompilerSupport.execute(CleaningJavaCompilerSupport.java:34)
at org.gradle.api.internal.tasks.compile.CleaningJavaCompilerSupport.execute(CleaningJavaCompilerSupport.java:25)
at org.gradle.api.tasks.compile.JavaCompile.performCompilation(JavaCompile.java:127)
at org.gradle.api.tasks.compile.JavaCompile.compile(JavaCompile.java:113)
at org.gradle.api.tasks.compile.JavaCompile.compile(JavaCompile.java:90)
at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:63)
at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$IncrementalTaskAction.doExecute(AnnotationProcessingTaskFactory.java:235)
at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.execute(AnnotationProcessingTaskFactory.java:211)
at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$IncrementalTaskAction.execute(AnnotationProcessingTaskFactory.java:222)
at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.execute(AnnotationProcessingTaskFactory.java:200)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:80)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:61)
... 13 more
Caused by: java.lang.NullPointerException
at com.grosner.processor.definition.TypeConverterDefinition.getModelClassQualifiedName(TypeConverterDefinition.java:62)
at com.grosner.processor.model.ProcessorManager.addTypeConverterDefinition(ProcessorManager.java:97)
at com.grosner.processor.handler.TypeConverterHandler.onProcessElement(TypeConverterHandler.java:44)
at com.grosner.processor.handler.BaseContainerHandler.handle(BaseContainerHandler.java:27)
at com.grosner.processor.model.ProcessorManager.handle(ProcessorManager.java:216)
at com.grosner.processor.DBFlowProcessor.process(DBFlowProcessor.java:85)
at com.sun.tools.javac.processing.JavacProcessingEnvironment.callProcessor(JavacProcessingEnvironment.java:794)
at com.sun.tools.javac.processing.JavacProcessingEnvironment.discoverAndRunProcs(JavacProcessingEnvironment.java:705)
at com.sun.tools.javac.processing.JavacProcessingEnvironment.access$1800(JavacProcessingEnvironment.java:91)
at com.sun.tools.javac.processing.JavacProcessingEnvironment$Round.run(JavacProcessingEnvironment.java:1035)
at com.sun.tools.javac.processing.JavacProcessingEnvironment.doProcessing(JavacProcessingEnvironment.java:1176)
at com.sun.tools.javac.main.JavaCompiler.processAnnotations(JavaCompiler.java:1170)
at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:856)
at com.sun.tools.javac.main.Main.compile(Main.java:523)
... 32 more
Thanks.
My app is crashing as soon as the Application.onCreate
method is called:
@Override
public void onCreate() {
super.onCreate();
FlowManager.init(this); // <== crash here
// do some other stuff
}
Apparently it's looking for a Database.Holder
class (which clearly does not exist). Am I missing something?
This is the stacktrace. Tested on both 1.3.1 and 1.3.0.
java.lang.RuntimeException: Unable to create application com.my.app.App: java.lang.RuntimeException: java.lang.ClassNotFoundException: com.raizlabs.android.dbflow.config.Database$Holder
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4521)
at android.app.ActivityThread.access$1500(ActivityThread.java:144)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1339)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5221)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
Caused by: java.lang.RuntimeException: java.lang.ClassNotFoundException: com.raizlabs.android.dbflow.config.Database$Holder
at com.raizlabs.android.dbflow.config.FlowManager.getDatabaseHolder(FlowManager.java:90)
at com.raizlabs.android.dbflow.config.FlowManager.init(FlowManager.java:127)
at com.my.app.App.onCreate(App.java:36)
at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1011)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4518)
at android.app.ActivityThread.access$1500(ActivityThread.java:144)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1339)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5221)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
Caused by: java.lang.ClassNotFoundException: com.raizlabs.android.dbflow.config.Database$Holder
at java.lang.Class.classForName(Native Method)
at java.lang.Class.forName(Class.java:308)
at java.lang.Class.forName(Class.java:272)
at com.raizlabs.android.dbflow.config.FlowManager.getDatabaseHolder(FlowManager.java:88)
at com.raizlabs.android.dbflow.config.FlowManager.init(FlowManager.java:127)
at com.my.app.App.onCreate(App.java:36)
at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1011)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4518)
at android.app.ActivityThread.access$1500(ActivityThread.java:144)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1339)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5221)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
Caused by: java.lang.ClassNotFoundException: Didn't find class "com.raizlabs.android.dbflow.config.Database$Holder" on path: DexPathList[[zip file "/data/app/com.my.app-2/base.apk"],nativeLibraryDirectories=[/vendor/lib, /system/lib]]
at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
at java.lang.Class.classForName(Native Method)
at java.lang.Class.forName(Class.java:308)
at java.lang.Class.forName(Class.java:272)
at com.raizlabs.android.dbflow.config.FlowManager.getDatabaseHolder(FlowManager.java:88)
at com.raizlabs.android.dbflow.config.FlowManager.init(FlowManager.java:127)
at com.my.app.App.onCreate(App.java:36)
at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1011)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4518)
at android.app.ActivityThread.access$1500(ActivityThread.java:144)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1339)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5221)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
Suppressed: java.lang.ClassNotFoundException: com.raizlabs.android.dbflow.config.Database$Holder
at java.lang.Class.classForName(Native Method)
at java.lang.BootClassLoader.findClass(ClassLoader.java:781)
at java.lang.BootClassLoader.loadClass(ClassLoader.java:841)
at java.lang.ClassLoader.loadClass(ClassLoader.java:504)
The migration file can only contain single-line sql statements. This will work fine for simple sql statements, but the file will become pretty much unreadable if the queries are long. How about changing the code from here
private void executeSqlScript(SQLiteDatabase db, String file) {
try {
final InputStream input = FlowManager.getContext().getAssets().open(MIGRATION_PATH + "/" + file);
final BufferedReader reader = new BufferedReader(new InputStreamReader(input));
final String querySuffix = ";";
final String queryCommentPrefix = "--";
String line;
StringBuffer query = new StringBuffer();
while((line = reader.readLine()) != null){
line = line.trim();
boolean isEndOfQuery = line.endsWith(querySuffix);
if(line.startsWith(queryCommentPrefix)){
continue;
}
if(isEndOfQuery){
line = line.substring(0, line.length()-querySuffix.length());
}
query.append(" "+line);
if(isEndOfQuery){
db.execSQL(query.toString());
query = new StringBuffer();
}
}
if(query.length() > 0){
db.execSQL(query.toString());
}
} catch (IOException e) {
FlowLog.log(FlowLog.Level.E, "Failed to execute " + file, e);
}
}
The new gradle plugin will simplify the readme's build.gradle example for this library
This is an unnecessary restriction.
Just create your handler using:
Handler mHandler = new Handler(Looper.getMainLooper)
This will put the handler on the ui thread.
so you can remove this check method:
Currently, it appears that doing Condition.operation("Some sql string") will put your custom operators between the column name and the value you're trying to operate on.
This is not exactly what I expect in some cases, like for example if I wanted to compare strings regardless of their case, I'd want to use COLLATE NOCASE, which is supposed to be at the end of the sql statement, like so:
SELECT NAME FROM CAT_TEMPLATE WHERE NAME = 'Test' COLLATE NOCASE
Unfortunately, when I put this into code in that order (which I assumed would spit it out in that order):
Select("NAME").from(CategoryPreset.class).where(Condition.column("NAME")
.is(name).operation("COLLATE NOCASE"));
It ends up giving me this:
SELECT NAME FROM CAT_TEMPLATE WHERE NAME COLLATE NOCASE 'Test'
Which clearly isn't going to do much except cause my app to crash.
Perhaps there should be another method in Condition that adds on operations to the end of the statement instead of just putting them in between the column and the value?
Hi there!
DBFlow looks like a promising library! I will definitely give it a shot with one of my next projects. One thing I immediately found when looking into the querying wiki pages was the lacking support for RxJava and observables. As this is an emerging (and booming) pattern in Android development I would really love to see support for this!
Anybody interested too?
I'm trying to create TypeCoverter with ModelClass List instance that looks like this:
@com.raizlabs.android.dbflow.annotation.TypeConverter
public class IntListTypeConverter extends TypeConverter<String, ArrayList<Integer>>{
@Override
public String getDBValue(ArrayList<Integer> model) {
String dbValue = "";
for(int i : model) {
dbValue += i + ";";
}
dbValue = dbValue.substring(0, dbValue.length() - 1);
return dbValue;
}
@Override
public ArrayList<Integer> getModelValue(String data) {
ArrayList<Integer> modelValue = new ArrayList<>();
for(String s : data.split(";")){
modelValue.add(Integer.parseInt(s));
}
return modelValue;
}
The error I'm getting is:
Error:Execution failed for task ':app:compileStagingDebugJava'. java.lang.NullPointerException
And here is last part of stacktrace for more information:
Caused by: java.lang.NullPointerException at com.raizlabs.android.dbflow.processor.definition.TypeConverterDefinition.getModelClassQualifiedName(TypeConverterDefinition.java:60) at com.raizlabs.android.dbflow.processor.model.ProcessorManager.addTypeConverterDefinition(ProcessorManager.java:96) at com.raizlabs.android.dbflow.processor.handler.TypeConverterHandler.onProcessElement(TypeConverterHandler.java:43) at com.raizlabs.android.dbflow.processor.handler.BaseContainerHandler.handle(BaseContainerHandler.java:25) at com.raizlabs.android.dbflow.processor.model.ProcessorManager.handle(ProcessorManager.java:215) at com.raizlabs.android.dbflow.processor.DBFlowProcessor.process(DBFlowProcessor.java:85) at com.sun.tools.javac.processing.JavacProcessingEnvironment.callProcessor(JavacProcessingEnvironment.java:793) at com.sun.tools.javac.processing.JavacProcessingEnvironment.discoverAndRunProcs(JavacProcessingEnvironment.java:722) at com.sun.tools.javac.processing.JavacProcessingEnvironment.access$1700(JavacProcessingEnvironment.java:97) at com.sun.tools.javac.processing.JavacProcessingEnvironment$Round.run(JavacProcessingEnvironment.java:1029) at com.sun.tools.javac.processing.JavacProcessingEnvironment.doProcessing(JavacProcessingEnvironment.java:1163) at com.sun.tools.javac.main.JavaCompiler.processAnnotations(JavaCompiler.java:1108) at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:824) at com.sun.tools.javac.main.Main.compile(Main.java:439)
If I change ModelClass type to any other class build passes but i can't get it to work with List. Can you please help me?
Hi,
I'm invoking this method:
FlowManager.getDatabase(DATABASE_NAME).reset(context);
But nothing happens to my database.
I think the problem is in the method that deletes the database:
public void reset(Context context) {
if (!isResetting) {
isResetting = true;
context.deleteDatabase(getDatabaseName());
mHelper = new FlowSQLiteOpenHelper(this, mInternalHelperListener);
isResetting = false;
}
}
getDatabaseName() only returns the database name without the ".db" extension. If we append the ".db" extension to the name the database is deleted.
Can you look at this issue?
Thanks
I have successfully implemented DBFlow in one of my apps, completly replacing the old database code - good work.. I wrote a process to copy the data from the old one to the new objects.
I had a crash at startup, rather weird, then found when inserting the old data into the new dbflow table, the "_id" primary key value was being changed..
Thus original table
_id value
1 a
2 b
4 c
became
_id
1
2
3
which caused failures in lookups to this table from other tables. I had to implement a lookup list oldvalue->newvalue..
I would have expected that a value inserted into the primary key row will be kept, only updated if no value has been put in..
:)
Hi,
Is there any support for many to many relations ?
If not, How would you implement it ?
I thought about something like that:
With doctors having many patients and patients having many doctors, all through an appointment
Doctor.java
@Table
public class Doctor extends BaseModel {
@Column(columnType = Column.PRIMARY_KEY)
public int id;
public List<Appointment> appointments;
private List<Patient> patients;
public Doctor() {
super();
}
public List<Appointment> getAppointments() {
if (appointments == null) {
appointments = Select.all(Appointment.class, Condition.column(Appointment$Table.DOCTORID).is(id));
}
return appointments;
}
public List<Patient> getPatients() {
if (patients == null) {
// patients = { Select.all Patient INNER JOIN Appointments ON Patient.id = patientId }
}
return patients;
}
}
Patient.java
@Table
public class Patient extends BaseModel {
@Column(columnType = Column.PRIMARY_KEY)
public int id;
public List<Appointment> appointments;
private List<Doctor> doctors;
public Patient() {
super();
}
public List<Appointment> getAppointments() {
if (appointments == null) {
appointments = Select.all(Appointment.class, Condition.column(Appointment$Table.PATIENTID).is(id));
}
return appointments;
}
public List<Doctor> getDoctor() {
if (doctors == null) {
// patients = { Select.all Patient INNER JOIN Appointments ON Patient.id = patientId }
}
return doctors;
}
}
Appointment.java
@Table
public class Appointment extends BaseModel {
@Column(columnType = Column.PRIMARY_KEY_AUTO_INCREMENT)
public int id;
public int doctorId;
public int patientId;
@Column(columnType = Column.FOREIGN_KEY,
references = { @ForeignKeyReference(columnType = Appointment.class,
columnName = "appointment", foreignColumnName = "id") })
public Patient patient;
@Column(columnType = Column.FOREIGN_KEY,
references = { @ForeignKeyReference(columnType = Appointment.class,
columnName = "appointment", foreignColumnName = "id") })
public Doctor doctor;
public Appointment() {
super();
}
public Doctor getDoctor() {
return doctor;
}
public Patient getPatient() {
return patient;
}
}
Hi,
i just found out this library and it promises to do many thing in a powerful way.
BUT I'm worry about whether the DBFlow enables easily the use of Sync-Adapter, as you know the Sync-Adpater requires a stub ContentProvider implementation, and in fact i nicely have been using another ORM (ActiveAndroid) and it makes that easily.
How would DBFlow aim to do that (if do)?
Thanks in advance.
Found that I needed to call through to the super of onPreMigrate()
and a constructor is needed!
Keep up the good work!
:)
Adapter classes since 1.1.3 version are generated with error:
// Begin Saving Foreign Key References From Model
if (model.account != null) {
model.account.save(false);
statement.bindLong(5,((java.lang.Long)model.account.id));
} else {
statement.statement.bindLong(5,0);
}
// End
should be
// Begin Saving Foreign Key References From Model
if (model.account != null) {
model.account.save(false);
statement.bindLong(5,((java.lang.Long)model.account.id));
} else {
statement.bindLong(5,0);
}
// End
The difference is in last line statement.statement.bindLong(5,0);
there should be one statement
It is not clear how to edit my gradle build files to include this project.
This statement needs clarification I think:
"Add the library to the project-level build.gradle, using the apt plugin and the AARLinkSources plugin::"
Please provide a sample project level and module level gradle.build files that use the library
In DBFlow / library / src / main / java / com / grosner / dbflow / sql / language / Where.java at Where.java, I found an error with orderBy. As per https://www.sqlite.org/lang_select.html, it is not DSC, but DESC.
/**
* Defines a SQL ORDER BY statement without the ORDER BY.
*
* @param ascending If we should be in ascending order
* @return
*/
public Where<ModelClass> orderBy(boolean ascending, String... columns) {
mOrderBy = new QueryBuilder().appendArray(columns).appendSpace().append(ascending ? "ASC" : "DSC").getQuery();
return this;
}
This should be the following:
/**
* Defines a SQL ORDER BY statement without the ORDER BY.
*
* @param ascending If we should be in ascending order
* @return
*/
public Where<ModelClass> orderBy(boolean ascending, String... columns) {
mOrderBy = new QueryBuilder().appendArray(columns).appendSpace().append(ascending ? "ASC" : "DESC").getQuery();
return this;
}
Otherwise, you get an error like this:
E/SQLiteLog﹕ (1) near "DSC": syntax error
When creating a FlowTableList on an empty table with cache=true
propertiesTableList = new FlowTableList<PropertiesTable>(PropertiesTable.class);
Caused by: java.lang.IllegalArgumentException: maxSize <= 0
at com.raizlabs.android.dbflow.structure.cache.LruCache.<init>(LruCache.java:51)
at com.raizlabs.android.dbflow.structure.cache.ModelLruCache.<init>(ModelLruCache.java:12)
at com.raizlabs.android.dbflow.list.FlowTableList.getBackingCache(FlowTableList.java:103)
at com.raizlabs.android.dbflow.list.FlowTableList$2.getBackingCache(FlowTableList.java:82)
at com.raizlabs.android.dbflow.list.FlowCursorList.setCacheModels(FlowCursorList.java:120)
at com.raizlabs.android.dbflow.list.FlowCursorList.setCacheModels(FlowCursorList.java:101)
at com.raizlabs.android.dbflow.list.FlowCursorList.<init>(FlowCursorList.java:65)
at com.raizlabs.android.dbflow.list.FlowCursorList.<init>(FlowCursorList.java:77)
at com.raizlabs.android.dbflow.list.FlowTableList$2.<init>(FlowTableList.java:79)
at com.raizlabs.android.dbflow.list.FlowTableList.<init>(FlowTableList.java:79)
How can I set Indexes for tables?
I use
Model model = new Model();
model.save(false);
to insert new data to the table. It is possible to get the id of the inserted entry?
gradle build
RELEASE BUILD
RELEASE BUILD
RELEASE BUILD
Download https://repo1.maven.org/maven2/com/google/auto/service/auto-service/1.0-rc2/auto-service-1.0-rc2.pom
Download https://repo1.maven.org/maven2/com/google/auto/auto-parent/2/auto-parent-2.pom
Download https://repo1.maven.org/maven2/com/google/auto/auto-common/0.3/auto-common-0.3.pom
Download https://repo1.maven.org/maven2/com/google/guava/guava/18.0/guava-18.0.pom
Download https://repo1.maven.org/maven2/com/google/guava/guava-parent/18.0/guava-parent-18.0.pom
Download https://repo1.maven.org/maven2/com/google/auto/service/auto-service/1.0-rc2/auto-service-1.0-rc2.jar
Download https://repo1.maven.org/maven2/com/google/auto/auto-common/0.3/auto-common-0.3.jar
Download https://repo1.maven.org/maven2/com/google/guava/guava/18.0/guava-18.0.jar
[]
[]
[]
[]
[]
[]
:app:preBuild
:app:compileDebugNdk
:app:preDebugBuild
:app:checkDebugManifest
:app:preReleaseBuild
:flowcore:compileJava
warning: [options] bootstrap class path not set in conjunction with -source 1.7
1 warning
:flowcore:processResources UP-TO-DATE
:flowcore:classes
:flowcore:jar
:library:compileLint
:library:copyReleaseLint UP-TO-DATE
:flowcore:javadoc
:flowcore:javadocJar
:flowcore:sourcesJar
:library:preBuild
:library:preReleaseBuild
:library:checkReleaseManifest
:library:prepareReleaseDependencies
:library:compileReleaseAidl
:library:compileReleaseRenderscript
:library:generateReleaseBuildConfig
:library:generateReleaseAssets UP-TO-DATE
:library:mergeReleaseAssets
:library:generateReleaseResValues
:library:generateReleaseResources
:library:packageReleaseResources
:library:processReleaseManifest
:library:processReleaseResources
:library:generateReleaseSources
:library:compileReleaseJava
/Users/arnoid/work/workspace/DBFlow/library/src/main/java/com/grosner/dbflow/structure/container/JsonArrayModel.java:16: error: class JSONArrayModel is public, should be declared in a file named JSONArrayModel.java
public class JSONArrayModel implements Model {
^
/Users/arnoid/work/workspace/DBFlow/library/src/main/java/com/grosner/dbflow/sql/language/Where.java:200: warning: non-varargs call of varargs method with inexact argument type for last parameter;
mOrderBy = new QueryBuilder().appendArray(columns).appendSpace().append(ascending ? "ASC" : "DESC").getQuery();
^
cast to Object for a varargs call
cast to Object[] for a non-varargs call and to suppress this warning
/Users/arnoid/work/workspace/DBFlow/library/src/main/java/com/grosner/dbflow/sql/language/Join.java:78: warning: non-varargs call of varargs method with inexact argument type for last parameter;
.appendArray(mUsing)
^
cast to Object for a varargs call
cast to Object[] for a non-varargs call and to suppress this warning
Note: Some input files use unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
1 error
2 warnings
:library:compileReleaseJava FAILED
FAILURE: Build failed with an exception.
What went wrong:
Execution failed for task ':library:compileReleaseJava'.
Compilation failed; see the compiler error output for details.
Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
BUILD FAILED
Total time: 18.881 secs
gradle --version
Build time: 2014-09-08 10:40:39 UTC
Build number: none
Revision: e6cf70745ac11fa943e19294d19a2c527a669a53
Groovy: 2.3.6
Ant: Apache Ant(TM) version 1.9.3 compiled on December 23 2013
JVM: 1.8.0_25 (Oracle Corporation 25.25-b02)
OS: Mac OS X 10.10.1 x86_64
java -version
java version "1.8.0_25"
Java(TM) SE Runtime Environment (build 1.8.0_25-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.25-b02, mixed mode)
android SDK build-tools 21.1.1
android SDK platform-tools 21
android SDK tools 21
com.raizlabs.android.dbflow.processor.utils.ModelUtils#writeContentValueStatement
does not create null value checks for types (e.g. non-primitive values) like Integer, Long, etc.
The compiler would need to check if the model property is a primitive (not nullable) or a type (nullable) variable and handle those two cases differently.
If a column is set to allow null values, the expected behavior would be to insert the null value to the database. Currently the generated adapter class throws a NPE inside the Model$Adapter#bindToStatement
method.
In the following method, it retrieves a Model from the Cursor for this List. However, the call "SqlUtils.convertToModel(false, mTable, mCursor);" should be "SqlUtils.convertToModel(true, mTable, mCursor);"
/**
* Returns a model at the specified position. If we are using the cache and it does not contain a model
* at that position, we move the cursor to the specified position and construct the {@link ModelClass}.
*
* @param position The row number in the {@link android.database.Cursor} to look at
* @return The {@link ModelClass} converted from the cursor
*/
public ModelClass getItem(int position) {
ModelClass model;
if (cacheModels) {
model = mModelCache.get(position);
if (model == null && mCursor.moveToPosition(position)) {
model = SqlUtils.convertToModel(false, mTable, mCursor);
mModelCache.put(position, model);
}
} else {
mCursor.moveToPosition(position);
model = SqlUtils.convertToModel(false, mTable, mCursor);
}
return model;
}
This should be the following:
/**
* Returns a model at the specified position. If we are using the cache and it does not contain a model
* at that position, we move the cursor to the specified position and construct the {@link ModelClass}.
*
* @param position The row number in the {@link android.database.Cursor} to look at
* @return The {@link ModelClass} converted from the cursor
*/
public ModelClass getItem(int position) {
ModelClass model;
if (cacheModels) {
model = mModelCache.get(position);
if (model == null && mCursor.moveToPosition(position)) {
model = SqlUtils.convertToModel(true, mTable, mCursor);
mModelCache.put(position, model);
}
} else {
mCursor.moveToPosition(position);
model = SqlUtils.convertToModel(true, mTable, mCursor);
}
return model;
}
Because, in SqlUtils.java, the convertToModel(boolean isList, Class table, Cursor cursor) method resets the Cursor to the first position if isList is false. Accordingly, this typo in FlowCursorList causes getItem(int position) to not work properly as any movement to a position specified for the Cursor is reset.
/**
* Takes first {@link ModelClass} from the cursor
*
* @param isList If it's a list, do not reset the cursor
* @param table The model class that we convert the cursor data into.
* @param cursor The cursor from the DB
* @param <ModelClass>
* @return
*/
@SuppressWarnings("unchecked")
public static <ModelClass extends Model> ModelClass convertToModel(boolean isList, Class<ModelClass> table, Cursor cursor) {
ModelClass model = null;
try {
if (isList || cursor.moveToFirst()) {
ModelAdapter<ModelClass> modelAdapter = FlowManager.getModelAdapter(table);
if(modelAdapter == null) {
Class persistentClass = (Class) ((ParameterizedType) table.getGenericSuperclass()).getActualTypeArguments()[0];
if(persistentClass.isAssignableFrom(BaseModelView.class)) {
model = (ModelClass) FlowManager.getModelViewAdapter((Class<? extends BaseModelView<? extends Model>>)table).loadFromCursor(cursor);
}
} else {
model = modelAdapter.loadFromCursor(cursor);
}
}
} catch (Exception e) {
FlowLog.log(FlowLog.Level.E, "Failed to process cursor.", e);
}
return model;
}
Let me begin by saying thank you for the effort that has clearly gone into this library. I think it shows great promise! Just a few questions;
Apologies for the dump of questions. Again, if you're looking for a hand on implementing any of this, please let me know and keep up the great work!
I have two tables ParentTable
and ChildTable
. The child table defines a foreign key relationship to one parent record (thus forming a 1-n
relationship):
@Table
public class ChildTable extends BaseModel {
@Column(columnType = Column.PRIMARY_KEY) public Long id;
@Column(columnType = Column.FOREIGN_KEY, references = {@ForeignKeyReference(columnName = "parentId", foreignColumnName = "id", columnType = Long.class)})
public ParentTable parent;
}
When I try to save multiple child records using something like this
ParentTable parent = ...
parent.save(false);
List<ChildTable> children = ...
for(ChildTable child : children) child.save(false);
the ChildTable$Adapter
calls the parent.save(false)
method in it's bindToStatement()
method for every child record that is saved. This causes redundant update operations of the parent record.
Furthermore, if I override the ParentTable#save()
method and place my child saving logic there, it results in a stack overflow (infinite calls to child.save()
-> parent.save()
).
Both problems indicate that the code location for saving foreign records is not inside TableAdapter#bindToStatement()
Any ideas on this?
It would be nice if Condition.in could be set up with a list instead of adding items one-by-one with in
and and
.
Currently a @ModelView
requires a String query for its annotation. It would be nice to have an optional interface to implement that does the same thing so the SQL wrapper classes can be used.
It is possible to set a default for a column in a tablet?
How can I insert new data to a model?
Thanks for library. looks promising.
I wanted to hack a quick app with it but I could not get started.
Wiki fails to take me off the ground with basic setup and store/retrieve simple object (sprinkles doc does a good job as example). Why is FlowManager.init() not mentioned anywhere in wiki? code would not run without this for me
I believe a simple example app would be a great first step.
Find out where the library is not allowing GC on data, causing out of memory exceptions when running large amounts of transactions.
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.