Ormlite: FieldType является примитивным типом, но помечен как чужой.

Я хотел бы знать, что означает ошибка из заголовка - она ​​очень часто встречается в моем проекте, но не имеет абсолютно никакого смысла (очевидно, что связанные классы являются более нервными примитивными типами).

Мне кажется, что эта ошибка возникает, если некоторые отношения неправильно сконфигурированы (например, имя внешнего поля с ошибкой в ​​​​аннотации), но ошибка не дает никакой информации об этом. Поиск этих неправильных отношений занимает так много времени, что я мог бы потратить это время на написание моей модели в простом sql без какой-либо формы!

Я также столкнулся со странной ситуацией, в которой я не вижу ничего плохого, но снова возникает исключение «примитивный тип, помеченный как иностранный». Ниже эта ситуация.

Наряду со многими таблицами в модели (около 50 классов) я создаю эти две: Tab1:

@DatabaseTable()
public class Tab1 {
    @DatabaseField(generatedId = true)
    int id;

    @ForeignCollectionField(eager = false, foreignFieldName = "tab1")
    Collection<Tab2> tab2;

    public Tab1() {
    }

    public int getId() {
            return id;
    }

    public void setId(int id) {
            this.id = id;
    }

    public Collection<Tab2> getTab2() {
            return tab2;
    }
}

Вкладка 2:

@DatabaseTable()
public class Tab2 {
    @DatabaseField(generatedId = true)
    int id;

    @DatabaseField(foreign = true)
    Tab1 tab1;

    public Tab2() {
    }

    public Tab2(Tab1 tab1) {
            super();
            this.tab1 = tab1;
    }

    public int getId() {
            return id;
    }

    public void setId(int id) {
            this.id = id;
    }

    public Tab1 getTab1() {
            return tab1;
    }

    public void setTab1(Tab1 tab1) {
            this.tab1 = tab1;
    }
}

В DatabaseHelper я создаю дао:

public class DatabaseHelper extends OrmLiteSqliteOpenHelper {

    private static final String DATABASE_NAME = "samplename.db";
    private static final String BACKUP_DATABASE_NAME = "samplename_bak.db";
    private static final int DATABASE_VERSION = 2;
    private static String DB_PATH = "/data/data/com.samplepath/databases/";

// DAOs

Dao<Tab1, Integer> tab1Dao;
Dao<Tab2, Integer> tab2Dao;
    // many other daos

    public Dao<Tab1, Integer> getTab1Dao() {
            try {
                    if (tab1Dao == null) {
                            tab1Dao = DaoManager.createDao(connectionSource, Tab1.class);
                    }
                    return tab1Dao;
            } catch (SQLException e) {
                    return null;
            }
    }

    public Dao<Tab2, Integer> getTab2Dao() {
            try {
                    if (tab2Dao == null) {
                            tab2Dao = DaoManager.createDao(connectionSource, Tab2.class);
                    }
                    return tab2Dao;
            } catch (SQLException e) {
                    return null;
            }
    }
    //many other dao getters

    public DatabaseHelper(Context context) {
            super(context, DATABASE_NAME, null, DATABASE_VERSION, R.raw.ormlite_config);
            Log.i("dbTag", "Creating database from file...");
            SQLiteDatabase db = this.getWritableDatabase();
    }

    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase, ConnectionSource connectionSource) {
            try {
                    Log.i("dbTag", "Creating database....");
                    TableUtils.createTable(connectionSource, Tab1.class);
                    TableUtils.createTable(connectionSource, Tab2.class);
                    //other create tables
                    Log.i("Exception", "inserted");
            } catch (SQLException e) {
                    Log.i("Exception", "error - could not create database.");
                    Log.i("Exception", e.getMessage());
                    Log.e("Exception", "", e);
            }
    }

    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, ConnectionSource connectionSource, int oldVersion,
                    int newVersion) {
            try {
                    Log.i("dbTag", "onUpgrade");
                    Log.i("dbTag", "Dropping database....");
                    TableUtils.dropTable(connectionSource, Tab1.class, true);
                    TableUtils.dropTable(connectionSource, Tab2.class, true);
                    //other drops
                    Log.i("dbTag", "Creating database....");
                    onCreate(sqLiteDatabase, connectionSource);
            } catch (SQLException e) {
                    Log.e(DatabaseHelper.class.getName(), "Can't drop databases", e);
                    throw new RuntimeException(e);
            }
    }
}

Я также включаю эти два класса в config util и создаю файл ormlite_config.txt. Я управляю помощником базы данных в базовой активности вместе с roboguice:

public class BaseActivity<T extends OrmLiteSqliteOpenHelper, E extends BaseErrorHandler> extends OrmLiteBaseActivity<T> implements RoboContext, IErrorHandler {

    protected EventManager eventManager;
    protected HashMap<Key<?>,Object> scopedObjects = new HashMap<Key<?>,Object>();
    protected E errorHandler;
    public static final DefaultHttpClient httpclient = new DefaultHttpClient();
    public static Map<String,String> args = null;

    @Inject
    ContentViewListener ignored; // do not use?

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        final RoboInjector injector = RoboGuice.getInjector(this);
        eventManager = injector.getInstance(EventManager.class);
        injector.injectMembersWithoutViews(this);
        super.onCreate(savedInstanceState);
        eventManager.fire(new OnCreateEvent(savedInstanceState));
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        eventManager.fire(new OnRestartEvent());
    }

    @Override
    protected void onStart() {
        super.onStart();
        eventManager.fire(new OnStartEvent());
    }

    @Override
    protected void onResume() {
        super.onResume();
        eventManager.fire(new OnResumeEvent());
    }

    @Override
    protected void onPause() {
        super.onPause();
        eventManager.fire(new OnPauseEvent());
    }

    @Override
    protected void onNewIntent( Intent intent ) {
        super.onNewIntent(intent);
        eventManager.fire(new OnNewIntentEvent());
    }

    @Override
    protected void onStop() {
        try {
            eventManager.fire(new OnStopEvent());
        } finally {
            super.onStop();
        }
    }

    @Override
    protected void onDestroy() {
        try {
            eventManager.fire(new OnDestroyEvent());
        } finally {
            try {
                RoboGuice.destroyInjector(this);
            } finally {
                super.onDestroy();
            }
        }
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        final Configuration currentConfig = getResources().getConfiguration();
        super.onConfigurationChanged(newConfig);
        eventManager.fire(new OnConfigurationChangedEvent(currentConfig, newConfig));
    }

    @Override
    public void onContentChanged() {
        super.onContentChanged();
        RoboGuice.getInjector(this).injectViewMembers(this);
        eventManager.fire(new OnContentChangedEvent());
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        eventManager.fire(new OnActivityResultEvent(requestCode, resultCode, data));
    }

    public Map<Key<?>, Object> getScopedObjectMap() {
        return scopedObjects;
    }

    @Override
    public void handleError(int resId) {
        errorHandler.exceptionHandler(getString(resId), this);
    }

}

В обеденной деятельности я запускаю код:

Log.i("Tab1", "creating tab1");
getHelper().getTab1Dao();
Log.i("Tab1", "created tab1");
Log.i("Tab1", "creating tab2");
getHelper().getTab2Dao();
Log.i("Tab1", "created tab2");

Приложение сначала удаляется с устройства, а затем устанавливается и запускается снова. Вот что я вижу в логах:

03-14 11:22:54.400: I/DaoManager(31657): Loaded configuration for class com.xxx.xxx.model.Tab1
03-14 11:22:54.400: I/DaoManager(31657): Loaded configuration for class com.xxx.xxx.model.Tab2
03-14 11:22:54.423: I/dbTag(31657): Creating database from file...
03-14 11:22:54.486: I/dbTag(31657): Creating database....
03-14 11:22:54.494: I/TableUtils(31657): creating table 'tab1'
03-14 11:22:54.494: I/TableUtils(31657): executed create table statement changed 1 rows: CREATE TABLE `tab1` (`id` INTEGER PRIMARY KEY AUTOINCREMENT ) 
03-14 11:22:54.494: I/TableUtils(31657): creating table 'tab2'
03-14 11:22:54.501: I/TableUtils(31657): executed create table statement changed 1 rows: CREATE TABLE `tab2` (`id` INTEGER PRIMARY KEY AUTOINCREMENT , `tab1_id` INTEGER ) 
[...]
03-14 11:22:55.283: I/Tab1(31657): creating tab1
03-14 11:22:55.291: E/Tab1(31657): java.lang.IllegalArgumentException: Field FieldType:name=tab1,class=Tab2 is a primitive class class com.xxx.xxx.model.Tab1 but marked as foreign
03-14 11:22:55.291: E/Tab1(31657):  at com.j256.ormlite.field.FieldType.configDaoInformation(FieldType.java:315)
03-14 11:22:55.291: E/Tab1(31657):  at com.j256.ormlite.dao.BaseDaoImpl.initialize(BaseDaoImpl.java:200)
03-14 11:22:55.291: E/Tab1(31657):  at com.j256.ormlite.dao.BaseDaoImpl.<init>(BaseDaoImpl.java:126)
03-14 11:22:55.291: E/Tab1(31657):  at com.j256.ormlite.dao.BaseDaoImpl.<init>(BaseDaoImpl.java:117)
03-14 11:22:55.291: E/Tab1(31657):  at com.j256.ormlite.dao.BaseDaoImpl$5.<init>(BaseDaoImpl.java:911)
03-14 11:22:55.291: E/Tab1(31657):  at com.j256.ormlite.dao.BaseDaoImpl.createDao(BaseDaoImpl.java:911)
03-14 11:22:55.291: E/Tab1(31657):  at com.j256.ormlite.dao.DaoManager.doCreateDao(DaoManager.java:359)
03-14 11:22:55.291: E/Tab1(31657):  at com.j256.ormlite.dao.DaoManager.createDaoFromConfig(DaoManager.java:326)
03-14 11:22:55.291: E/Tab1(31657):  at com.j256.ormlite.dao.DaoManager.createDao(DaoManager.java:55)
03-14 11:22:55.291: E/Tab1(31657):  at com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper.getDao(OrmLiteSqliteOpenHelper.java:239)
03-14 11:22:55.291: E/Tab1(31657):  at com.xxx.xxx.xxx.onCreate(XXX.java:43)
03-14 11:22:55.291: E/Tab1(31657):  at android.app.Activity.performCreate(Activity.java:4465)
03-14 11:22:55.291: E/Tab1(31657):  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1053)
03-14 11:22:55.291: E/Tab1(31657):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1934)
03-14 11:22:55.291: E/Tab1(31657):  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1995)
03-14 11:22:55.291: E/Tab1(31657):  at android.app.ActivityThread.access$600(ActivityThread.java:128)
03-14 11:22:55.291: E/Tab1(31657):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1161)
03-14 11:22:55.291: E/Tab1(31657):  at android.os.Handler.dispatchMessage(Handler.java:99)
03-14 11:22:55.291: E/Tab1(31657):  at android.os.Looper.loop(Looper.java:137)
03-14 11:22:55.291: E/Tab1(31657):  at android.app.ActivityThread.main(ActivityThread.java:4514)
03-14 11:22:55.291: E/Tab1(31657):  at java.lang.reflect.Method.invokeNative(Native Method)
03-14 11:22:55.291: E/Tab1(31657):  at java.lang.reflect.Method.invoke(Method.java:511)
03-14 11:22:55.291: E/Tab1(31657):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:790)
03-14 11:22:55.291: E/Tab1(31657):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:557)
03-14 11:22:55.291: E/Tab1(31657):  at dalvik.system.NativeStart.main(Native Method)

Кроме того, у меня есть собственные дао для всех других классов в модели, но я не использую их для этих двух классов. У меня также есть интерфейс для каждого другого класса в модели (я знаю, что это странно, но для некоторых целей он должен быть у меня).

Любая помощь будет принята с благодарностью, спасибо!


person matt112358    schedule 14.03.2013    source источник
comment
Я не знаю ответа, но когда у меня возникали подобные проблемы, установка точки останова в исходном коде ormlite (в данном случае FieldType.java) помогла мне понять, что он пытался сделать. По крайней мере, он должен позволять вам видеть, какие поля он просматривает и как, по его мнению, они объявлены.   -  person matt helliwell    schedule 14.03.2013


Ответы (3)


Хм. Что ж, ошибка предполагалась не требующая пояснений.

Field FieldType:name=tab1,class=Tab2 is a primitive class 
    class com.xxx.xxx.model.Tab1 but marked as foreign

По какой-то причине тип Tab2 имеет поле tab1, помеченное как примитивный класс. Однако в вашем классе поле tab1 определяется как:

@DatabaseField(foreign = true)
Tab1 tab1;

Есть ли шанс, что вы не обновили файл конфигурации базы данных, связанный с этим классом? Может быть, раньше это был int, а теперь Tab1? Вам нужно будет перегенерировать файл конфигурации при изменении схемы.

person Gray    schedule 14.03.2013
comment
Файл конфигурации обязательно обновляется. Эти две таблицы были просто тестовыми примерами, добавленными к существующему коду. Поле tab1 всегда имело тип Tab1. Однако, когда я добавил эти классы в пустой проект, они работали правильно. Я думаю, что это может быть связано с интерфейсом, добавленным ко всем классам в модели (эти два не реализуют его, но, возможно, форма все равно запуталась из-за этого интерфейса) или с нарушенным отношением в каком-то другом классе, который приводит к разрыву формы . Кроме того, когда я создаю дао, перехватываю Exception и создаю его снова - он создается правильно. - person matt112358; 14.03.2013
comment
Извините, @matt112358. Без понятия. - person Gray; 14.03.2013

Я столкнулся с той же проблемой, хотя я не знаю, в чем именно проблема, но я уверен, что она вызвана файлом ormlite_config.txt. Как только я удалю файл и изменю конструктор вспомогательного класса базы данных, чтобы он не использовал версию ormlite_config.txt. все просто отлично работает.

person Aaron Shen    schedule 31.07.2013

Если кто-то столкнется с подобной проблемой: не вызывайте this.getWritableDatabase() в конструкторе DatabaseHelper. Когда я удалил это, код волшебным образом начал работать - понятия не имею, почему это произошло, но он работает.

person matt112358    schedule 06.04.2013