Android Studio i SQLite

0

Cześć. Tworzę prosty program do dodawania/usuwania rekordów w bazie. Jest napisany kod, który powinien działać, lecz po dodaniu jakiejś wartości wyskakuje error że kolumny name po prostu nie ma. Przeglądałem kod i nie umiem znaleźć błędu.
Klasa MainActivity

package com.example.rukat.bazadanych;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Button;
import android.widget.EditText;
import android.view.View;
import android.database.Cursor;
import android.util.Log;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    public Button btnInsert;
    public Button btnDelete;
    public Button btnSelect;
    public Button btnSearch;
    public EditText editName;
    public EditText editAge;
    public EditText editDelete;
    public EditText editSearch;

    ZarzadzajDanymi dm;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        dm = new ZarzadzajDanymi(this);

        btnInsert = (Button) findViewById(R.id.insertButton);
        btnDelete = (Button) findViewById(R.id.deleteButton);
        btnSelect = (Button) findViewById(R.id.selectAllButton);
        btnSearch = (Button) findViewById(R.id.searchButton);

        editName = (EditText) findViewById(R.id.imieTextBox);
        editAge = (EditText) findViewById(R.id.wiekTextBox);
        editDelete = (EditText) findViewById(R.id.deleteTextBox);
        editSearch = (EditText) findViewById(R.id.searchTextBox);

        btnSelect.setOnClickListener(this);
        btnInsert.setOnClickListener(this);
        btnDelete.setOnClickListener(this);
        btnSearch.setOnClickListener(this);
    }
    public void showData(Cursor c){
        while (c.moveToNext()){
            Log.i(c.getString(1), c.getString(2));
        }
    }

    @Override
    public void onClick(View v)
    {
        switch (v.getId()){
            case R.id.insertButton:
                dm.insert(editName.getText().toString(),
                        editAge.getText().toString());
                break;
            case R.id.selectAllButton:
                showData(dm.selectAll());
                break;
            case R.id.searchButton:
                showData(dm.searchName(editSearch.getText().toString()));
                break;
            case R.id.deleteButton:
                dm.delete(editDelete.getText().toString());
                break;
        }
    }
}

Klasa Zarzadzaj Danymi

package com.example.rukat.bazadanych;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.content.Context;
import android.util.Log;
import android.database.Cursor;
/**
 * Created by rukat on 04.01.2018.
 */

public class ZarzadzajDanymi {
    private SQLiteDatabase db;

    public static final String TABLE_ROW_ID = "_id";
    public static final String TABLE_ROW_NAME = "name";
    public static final String TABLE_ROW_AGE = "age";

    private static final String DB_NAME = "address_book_db";
    private static final int DB_VERSION = 1;
    private static final String TABLE_N_AND_A = "names_and_addresses";


    private class CustomSQLiteOpenHelper extends SQLiteOpenHelper
    {
        public CustomSQLiteOpenHelper(Context context)
        {
            super(context,DB_NAME,null,DB_VERSION);
        }

        @Override
        public void onCreate(SQLiteDatabase db)
        {
            String newTableQueryString = "create table "
                    + TABLE_N_AND_A + " ("
                    + TABLE_ROW_ID
                    + " integer primary key autoincrement not null,"
                    + TABLE_ROW_AGE
                    + " text not null);";
            db.execSQL(newTableQueryString);
        }
        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
        {
        }
    }

    public ZarzadzajDanymi(Context context)
    {
        CustomSQLiteOpenHelper helper =
                new CustomSQLiteOpenHelper(context);
        db = helper.getWritableDatabase();
    }

    public void insert(String name, String age)
    {
        String query = "INSERT INTO " + TABLE_N_AND_A + " (" +
                TABLE_ROW_NAME + ", " + TABLE_ROW_AGE + ") " +
            "VALUES (" +
                "'" + name + "'" + ", " + "'" + age + "'" + ");";
        Log.i("insert() = ", query);
        db.execSQL(query);
    }

    public void delete(String name)
    {
        String query = "DELETE FROM " + TABLE_N_AND_A +
                " WHERE " + TABLE_ROW_NAME +
                " = '" + name + "';";
        Log.i("delete() = ", query);
        db.execSQL(query);
    }

    public Cursor selectAll() {
        Cursor c = db.rawQuery("SELECT *" + " from " +
        TABLE_N_AND_A,null);
        return c;
    }

    public Cursor searchName(String name) {
        String query = "SELECT " +
                TABLE_ROW_ID + ", " +
                TABLE_ROW_NAME +
                ", " + TABLE_ROW_AGE +
                " from " +
                TABLE_N_AND_A + " WHERE " +
                TABLE_ROW_NAME + " = '" + name + "';";
        Log.i("searchName() = ", query);
        Cursor c = db.rawQuery(query,null);
        return c;
    }
}

0

Ano nie ma....

            String newTableQueryString = "create table "
                    + TABLE_N_AND_A + " ("
                    + TABLE_ROW_ID
                    + " integer primary key autoincrement not null,"
                    + TABLE_ROW_AGE
                    + " text not null);";
0

No bo kolumny name nie ma. Zobacz jak składasz query do budowania tabeli. Tam nie wykorzystujesz pola o nazwie TABLE_ROW_NAME. Dodaj je do query w newTableQueryString i będzie pykać.

0

W kodzie tworzącym tabelę dodajesz tylko kolumny id oraz age, więc jak to ma działać?

String newTableQueryString = "create table "
                    + TABLE_N_AND_A + " ("
                    + TABLE_ROW_ID
                    + " integer primary key autoincrement not null,"
                    + TABLE_ROW_AGE
                    + " text not null);";
            db.execSQL(newTableQueryString);
0
  String newTableQueryString = "create table "
                    + TABLE_N_AND_A + " ("
                    + TABLE_ROW_NAME
                    + TABLE_ROW_ID
                    + " integer primary key autoincrement not null,"
                    + TABLE_ROW_AGE
                    + " text not null);";

Faktycznie nie było - chociaż po dodaniu nadal nie śmiga. Może to jakaś błahostka, ale mam zero doświadczenia z tym.

0

To dlatego, że źle to robisz. Dodałeś samą nazwę kolumny, ale nie określiłeś jej typu oraz nie dodałeś przecinka. Poczytaj jakieś kursu dla początkujących odnośnie SQL, w szczególności tego jak zakładać nowe tabele (CREATE TABLE).

0
          String newTableQueryString = "create table "
                    + TABLE_N_AND_A + " ("
                    + TABLE_ROW_ID
                    + " integer primary key autoincrement not null,"
                    + TABLE_ROW_NAME
                    + " text not null,"
                    + TABLE_ROW_AGE
                    + " text not null);";
            db.execSQL(newTableQueryString);

Wszystko już działa. Wcześniej też miałem NAME wpisany tutaj, lecz w Android Studio trzeba z telefonu całkowicie przeinstalować aplikacje żeby baza danych stworzyła się na nowo o czym nie wiedziałem, dlatego też ten błąd cały czas był. Dzięki wszystkim za pomoc

0

Ktoś jeszcze to robi, zamiast używać ormLite lub innego podobnego rozwiązania?

1

@panryz: a jak ktoś wie jak to działa to też musi z tego korzystać bezpośrednio? Czy już można normalnie użyć orm?

0

Nie wiem jak inni, ale ja miałem bardzo mało przypadków, gdy NAPRAWDĘ użycie sqlite było czymś uzasadnione. Bo jeśli tylko trzeba zapisać jakiś obiekt zawierający dane, to i tak lepsze jest SnappyDB.https://github.com/systembugtj/SnappyDB/blob/master/README.md

Prawie nigdy użycie sqlite nie ma żadnego uzasadnienia, chyba ze ktoś potrzebuje relacyjnej bazy danych albo integruje się z jakimś content providerem

0

Inna alternatywa dla SQLite to https://realm.io/docs/java/latest/

Dodanie każdej kolejnej biblioteki wiąże się z pewnym narzutem, więc jeśli w aplikacji potrzebujemy raptem jednej tabelki na trzy kolumny, to sięganie po jakiegoś ORM-a (czy w ogóle NoSQL) wydaje mi się strzelaniem z armaty do wróbli, i jednak dwa razy bym się przed tym zastanowił.

Mogą być też inne okoliczności. Kilka lat temu pracowałem nad projektem, w którym baza była szyfrowana z użyciem SQLCipher - pamiętam, że mimo wysiłków nie zdołaliśmy zmusić tego do współpracy z żadnym ORM (trochę walczyłem z forkiem któregoś z nich, w końcu machnąłem ręką). Koniec końców sami napisaliśmy prostą warstwę abstrakcji, która nieco cywilizowała nam obsługę surowego SQLite.

Sama baza, warto dodać, była dość skomplikowana i stosowaliśmy sporo JOIN-ów jak i innych nietrywialnych zapytań, z czym ORM-y notorycznie mają problem. Przypuszczam, że ze względów wydajnościowych i tak bylibyśmy nieraz zmuszeni, by sięgać do bazy bezpośrednio, "ponad głową" ORM-a.

A wreszcie kod kolegi jest, jak sądzę, elementem nauki - bo trudno mi sobie wyobrazić, by w prawdziwym, komercyjnym projekcie ktoś miał klasę o nazwie ZarzadzajDanymi :)

0

No ok, ale czy jedna tabelka na 3 kolumny to nie wystarczy zserializować do shared preferences? Chyba ze ta tabelka będzie mieć 100 tysięcy rekordów

0

A jeśli np. trzeba wykonywać na tych rekordach (nawet przy ich możliwie niskiej liczbie) jakieś zapytania filtrujące czy agregujące? Pisanie tego ręcznie to byłoby wynajdywanie koła na nowo. Boilerplate, którego uniknęliśmy, omijając potrzebę założenia bazy, urodzi się nam gdzie indziej - na dodatek wprowadzając ryzyko jakichś bugów (podczas gdy silnik zapytań SQLite jest raczej porządnie przetestowany...)

0

No tak, ale jeśli nie ma tego dużo, to pewnie i tak lepiej zdeserializować wszystko do jakiejś tablicy i potem ją filtrować, agregować czy co tam jeszcze, z lambda i guava collections (lub stream api z javy 8 jeśli obsługa Androida starszego niż 7 nie jest konieczna) to praktycznie kilka linijek kodu.

P.S. ciężko mi sobie wyobrazić, co i jak mógłbyś agregować i filtrować w jakiś zaawansowany sposób z jednej tylko tabeli z 3 kolumnami, no ale to juz zalezy od konkretnego przypadku.

0

Nie wiem, choćby jakaś lokalna historia operacji na koncie użytkownika, którą można sobie filtrować ze względu na zakres czasowy, typ operacji; zsumować jakieś wpłaty, itd.

Drugi argument jest taki, że nawet proste struktury danych mogą wymagać jakichś zmian, kiedy następuje upgrade wersji - w przypadku SQLite mamy to już rozwiązane, baza jest wersjonowana, onUpgrade będzie wywołany gdy potrzeba, a zmiana struktury w przypadku oparcia jej o preferencje byłaby żmudna, prawdopodobnie wymagając "przepisania" danych od nowa.

Dla prostych przypadków jest to sensowne rozwiązanie - ja mówię tylko, by go nie nadużywać wskutek lenistwa ;)

0

Nie wiem jak bardzo "ważny" to jest projekt - hobbystyczny, zaliczenie na studia - ale mozesz poczytac o https://developer.android.com/training/data-storage/room/index.html

BTW Polskie nazwy klas są ZŁE

0

jw. pisz po angielksu, chyba ze chcesz pracowac dla zusu czy pkp...
zapoznaj sie tez z biblioteka Butter Knife do view injection

1 użytkowników online, w tym zalogowanych: 0, gości: 1