sql >> Databasteknik >  >> RDS >> SQLite

Rum - Använder externa SQLites såväl som intern DB

Vad vi behöver:

Vi måste kunna använda koppla de externa databaserna till den interna rumsdatabasen utan att ändra sökvägen de är lagrade i. Efter att ha lagt till dem vill vi kunna använda databaserna med Room Entity, Dao och Database-objekten. Finns det något sätt att uppnå detta?

Det kan vara lättare att inte bifoga, anledningen är att du kan använda en separat rumsdatabasinstans. Utan du skulle behöva ha separata DAO för att tillgodose det bifogade schemanamnet (tror jag). Säger att exemplet nedan (baserat på något jag lekte med för någon och därav de ganska förvirrande kolumnnamnen) .

t.ex. förutsatt att ATTACH DATABASE .... AS other (det bifogade schemat är annat ) sedan istället för (för huvuddatabasen)

@Query("SELECT * FROM AllUsers")
List<AllUsers> getAllAllUsers();

Du skulle behöva en gratis :-

@SkipQueryVerification
@Query("SELECT * FROM other.AllUsers")
List<AllUsers> getOtherAllAllUsers();

etc.

Men om du istället hade något liknande (för huvuddelen) :-

    mLPDB = Room.databaseBuilder(this,LoanPaymentDatabase.class,"mydb").allowMainThreadQueries().build();
    mLPDB_DAO = mLPDB.mDao();

Tillsammans med (för den andra) :-

    mOtherDB = Room.databaseBuilder(this,LoanPaymentDatabase.class,OtherDatabaseHelper.DBNAME).allowMainThreadQueries().build();
    mOtherDAO = mOtherDB.mDao();

Sedan kan du komma åt båda med samma DAO.

  • Obs naturligtvis förutsätter ovanstående att schemat är komplementärt (inte nödvändigtvis exakt).

Inte nödvändigtvis exakt?

Täcker även kommentaren :-

Du måste migrera data till själva rummet först.

  • Med lite lek kan du komma runt måste migrera genom att lura room genom att ställa in user_version till 0. I vilket fall Room ställer in versionsnumret (begränsad testning). Jag är dock inte säker på vad GreenDao eller din server skulle göra om detta (din läxa).

  • Min begränsade testning gällde ett vanligt problem vid migrering av att ha en kolumn med INTEGER PRIMARY KEY, dvs utan AUTOINCREMENT. Rum om migrering kommer att klaga på att schemat inte matchar. Så jag kodade avsiktligt inte AUTOINCREMENT, ställde in user_version till 0 och inga klagomål som fick tillgång till databasen via Room. Använde även kolumntypen rumplestilskin och inga klagomål.

Som sådan tror jag att du kan komma runt migreringsproblem med det fruktade förväntade/hittade genom att ställa in user_version till 0 (och därför tror jag att kringgå migration). Uppenbarligen måste kolumnnamnen matcha, om de definieras i en Entity och inte ignoreras.

  • Jag har också försökt att lägga till en kolumn som inte är definierad för enheten och använda ovanstående resultat utan att klaga (dessa tester bör vara uppenbara i koden nedan).

Exempel

Följande är ett exempel på en 2 Entity Room Database och i syfte att testa den andra databas en byggd utanför rummet som tillräckligt matchar rumsdatabasen för att kunna användas, dvs. Entitetskolumnnamn matchas.

Den andra databasen

Den andra databasen utanför rummet skapas via en SQLiteOpenHelper underklass enligt OtherDatabaseHelper.java :-

public class OtherDatabaseHelper extends SQLiteOpenHelper {

    public static final String DBNAME = "lpolddb";
    public static final int DBVERSION = 1;
    public static final String ALLUSERS_TBL = "AllUsers";
    public static final String PAIDUNPAID_TBL = "PaidUnpaid";

    /*
        @PrimaryKey(autoGenerate = true)
        private long auid;
        private String Name;
        private int Loan;
        private int TimeInMonths;
     */
    public static final String ALLUSERS_COL_AUID = "auid";
    public static final String ALLUSERS_COL_NAME = "Name";
    public static final String ALLUSERS_COL_LOAN = "Loan";
    public static final String ALLUSERS_COL_TIMEINMONTHS = "TimeInMonths";

    private static final String crt_allusers_table_sql =
            "CREATE TABLE IF NOT EXISTS " + ALLUSERS_TBL + "(" +
                    //ALLUSERS_COL_AUID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
                    ALLUSERS_COL_AUID + " INTEGER PRIMARY KEY," +
                    ALLUSERS_COL_NAME + " TEXT, " +
                    ALLUSERS_COL_LOAN + " INTEGER, " +
                    "someothercolumnnotdefineinroom TEXT, " + //!!!!!!!!!! not a column in an entity
                    ALLUSERS_COL_TIMEINMONTHS + " INTEGER" +
                    ")";

    /*
        @PrimaryKey(autoGenerate = true)
        private long puid;
        private int TimeInMonths;
        private String PaidUnpaid;
        @ForeignKey(
            entity = AllUsers.class,
            parentColumns = {"auid"},
            childColumns = {"AllUsersReference"},
            onUpdate = ForeignKey.CASCADE, onDelete = ForeignKey.CASCADE)
        private long AllUsersReference;
     */

    public static final String PAIDUNPAID_COL_PUID = "puid";
    public static final String PAIDUNPAID_TIMEINMONTHS = ALLUSERS_COL_TIMEINMONTHS;
    public static final String PAIDUNPAID_COL_PAIDUNPAID = "PaidUnpaid";
    public static final String PAIDUNPAID_COL_ALLUSERSREFERENCE = "AllUsersReference";

    public static final String crt_paidunpaid_table_sql =
            "CREATE TABLE IF NOT EXISTS " + PAIDUNPAID_TBL + "(" +
                    PAIDUNPAID_COL_PUID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
                    PAIDUNPAID_TIMEINMONTHS + " rumplestilskin, " + // !!!!!!!!!!!
                    PAIDUNPAID_COL_PAIDUNPAID + " TEXT," +
                    PAIDUNPAID_COL_ALLUSERSREFERENCE + " INTEGER " +
                    " REFERENCES " + ALLUSERS_TBL + "(" + ALLUSERS_COL_AUID + ") " +
                    "ON UPDATE CASCADE ON DELETE CASCADE" +
                    ")";


    SQLiteDatabase mDB;
    public OtherDatabaseHelper(Context context) {
        super(context, DBNAME, null, DBVERSION);
        mDB = this.getWritableDatabase();
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(crt_allusers_table_sql);
        db.execSQL(crt_paidunpaid_table_sql);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }

    public long insertAllUsers(String name, int loanamount, int periodofloan) {
        ContentValues cv = new ContentValues();
        cv.put(ALLUSERS_COL_NAME,name);
        cv.put(ALLUSERS_COL_LOAN,loanamount);
        cv.put(ALLUSERS_COL_TIMEINMONTHS,periodofloan);
        return mDB.insert(ALLUSERS_TBL,null,cv);
    }

    public long insertPaidUnpaid(int formonth, String status, long allUserreferenced) {
        ContentValues cv = new ContentValues();
        cv.put(PAIDUNPAID_TIMEINMONTHS,formonth);
        cv.put(PAIDUNPAID_COL_PAIDUNPAID,status);
        cv.put(PAIDUNPAID_COL_ALLUSERSREFERENCE,allUserreferenced);
        return mDB.insert(PAIDUNPAID_TBL,null,cv);
    }
}
  • se kommentarer för konstigheter/avsiktligt tillagda avvikelser
  • denna fylls i, nås av en alternativ rumsdatabas och via bifogad DB i MainActivity.java nedan

Rumsdatabasen

De två enheterna:-

AllUsers.java

@Entity
public class AllUsers {
    @PrimaryKey(autoGenerate = true)
    private long auid;
    private String Name;
    private int Loan;
    private int TimeInMonths;

    public AllUsers() {
    }

    @Ignore
    public AllUsers(String Name, int Loan, int TimeInMonths) {
        this.Name = Name;
        this.Loan = Loan;
        this.TimeInMonths = TimeInMonths;
    }

    public long getAuid() {
        return auid;
    }

    public void setAuid(long auid) {
        this.auid = auid;
    }

    public String getName() {
        return Name;
    }

    public void setName(String name) {
        Name = name;
    }

    public int getLoan() {
        return Loan;
    }

    public void setLoan(int loan) {
        Loan = loan;
    }

    public int getTimeInMonths() {
        return TimeInMonths;
    }

    public void setTimeInMonths(int timeInMonths) {
        TimeInMonths = timeInMonths;
    }
}

och PaidUnpaid.java :-

@Entity
public class PaidUnpaid {
    @PrimaryKey(autoGenerate = true)
    private long puid;
    private int TimeInMonths;
    private String PaidUnpaid;
    @ForeignKey(
            entity = AllUsers.class,
            parentColumns = {"auid"},
            childColumns = {"AllUsersReference"},
            onUpdate = ForeignKey.CASCADE, onDelete = ForeignKey.CASCADE)
    private long AllUsersReference;


    public PaidUnpaid() {
    }

    @Ignore
    public PaidUnpaid(int TimeInMonths, String PaidUnpaid, long AllUsersreference) {
        this.TimeInMonths = TimeInMonths;
        this.PaidUnpaid = PaidUnpaid;
        this.AllUsersReference = AllUsersreference;
    }

    public long getPuid() {
        return puid;
    }

    public void setPuid(long puid) {
        this.puid = puid;
    }

    public int getTimeInMonths() {
        return TimeInMonths;
    }

    public void setTimeInMonths(int timeInMonths) {
        TimeInMonths = timeInMonths;
    }

    public String getPaidUnpaid() {
        return PaidUnpaid;
    }

    public void setPaidUnpaid(String paidUnpaid) {
        PaidUnpaid = paidUnpaid;
    }

    public long getAllUsersReference() {
        return AllUsersReference;
    }

    public void setAllUsersReference(long allUsersReference) {
        AllUsersReference = allUsersReference;
    }
}

En ytterligare POJO-klass, AllUsersAndPaidUnpaidsList.java som man lekte med så inkorporerad och använd :-

public class AllUsersAndPaidUnpaidsList {

    @Embedded
    AllUsers allUsers;
    @Ignore
    @PrimaryKey
    long auid;

    @Ignore
    @Relation(entity = PaidUnpaid.class,parentColumn = "auid",entityColumn = "puid")
    List<PaidUnpaid> paidUnpaidList;

    @Ignore
    public AllUsersAndPaidUnpaidsList(AllUsers au, List<PaidUnpaid> pulist) {
        this.allUsers = au;
        this.paidUnpaidList = pulist;
    }

    public List<PaidUnpaid> getPaidUnpaidList() {
        return this.paidUnpaidList;
    }


    public void setPaidUnpaidList(List<PaidUnpaid> paidUnpaidList) {
        this.paidUnpaidList = paidUnpaidList;
    }

    public AllUsers getAllUsers() {
        return allUsers;
    }

    public void setAllUsers(AllUsers allUsers) {
        this.allUsers = allUsers;
    }

    public void outputToLog(String tag) {
        StringBuilder sb = new StringBuilder("AllUsersName = ")
                .append(this.allUsers.getName())
                .append(" TimeInMonths = ")
                .append(String.valueOf(this.allUsers.getTimeInMonths()))
                ;
        for (PaidUnpaid pu: this.getPaidUnpaidList()) {
            sb.append("\n\t TimeInMonths = ")
                    .append(String.valueOf(pu.getTimeInMonths()))
                    .append(" Paid/Unpaid = ")
                    .append(pu.getPaidUnpaid());
        }
        Log.d(tag,sb.toString());
    }
}

Ett enda gränssnitt Dao.java :-

@androidx.room.Dao
public interface Dao {

    @Insert(onConflict = OnConflictStrategy.IGNORE)
    long[] insertAllUsers(AllUsers... allUsers);

    @Insert(onConflict = OnConflictStrategy.IGNORE)
    long insertAllUsers(AllUsers allUsers);

    @Insert(onConflict = OnConflictStrategy.IGNORE)
    long[] insertPaidUnpaid(PaidUnpaid... paidUnpaids);

    @Insert(onConflict = OnConflictStrategy.IGNORE)
    long insertPaidUnpaid(PaidUnpaid paidUnpaid);

    @Update(onConflict = OnConflictStrategy.IGNORE)
    int updateAllUsers(AllUsers... allUsers);

    @Update(onConflict =  OnConflictStrategy.IGNORE)
    int updateAllUsers(AllUsers allUsers);

    @Update(onConflict = OnConflictStrategy.IGNORE)
    int updatePaidUnpaid(PaidUnpaid... paidUnpaids);

    @Update(onConflict = OnConflictStrategy.IGNORE)
    int updatePaidUnpaid(PaidUnpaid paidUnpaid);

    @Delete
    int deleteAllUsers(AllUsers... allUsers);

    @Delete
    int deleteAllUsers(AllUsers allUsers);

    @Delete
    int deletePaidUnpaid(PaidUnpaid... paidUnpaids);

    @Delete
    int deletePaidUnpaid(PaidUnpaid paidUnpaid);

    @Query("SELECT * FROM AllUsers")
    List<AllUsers> getAllAllUsers();

    @Query("SELECT * FROM AllUsers WHERE auid = :id")
    List<AllUsers> getOneAllUsersById(long id);

    @Query("SELECT * FROM PaidUnpaid")
    List<PaidUnpaid> getAllPaidUnpaids();

    @Query("SELECT * FROM PaidUnpaid WHERE puid = :id")
    List<PaidUnpaid> getOnePaidUnpaidById(long id);

    @Query("SELECT * FROM PaidUnpaid WHERE AllUsersReference = :allUsersid")
    List<PaidUnpaid> getPaidUnpaidsForAllUsersId(long allUsersid);

    /*************
     * Some Additional DAO's for attached not required for alternative helper
     * in practice you would likely need attached versions of all
     ************/

    @Query("SELECT * FROM other.PaidUnpaid WHERE AllUsersReference = :allUsersid")
    @SkipQueryVerification
    List<PaidUnpaid> getOtherPaidUnpaidForAllUsersId(long allUsersid);

    @SkipQueryVerification
    @Query("SELECT * FROM other.AllUsers")
    List<AllUsers> getOtherAllAllUsers();
}

Rumsdatabasklassen LoanPaymentDatabase.java

@Database(entities = {AllUsers.class,PaidUnpaid.class},exportSchema = false,version = 1)
public abstract class LoanPaymentDatabase extends RoomDatabase {
    public abstract Dao mDao();
}

Sammanfogar allt

Äntligen en aktivitet som :-

  1. Skapar och fyller i andra (icke-rum) databas (om den inte finns) för testning. Ställa in user_version (databasversion i Android Talk) till 0.

  2. Skapar, om det behövs, Room-versionen av databasen.

  3. Lägger till ett par rader i rumsversionen.
  4. Matar ut data i rumsversionen till loggen.
  5. Skapar en alternativ RoomDatabase med other databas.
  6. Matar ut data i other databas via Room.
  7. Bifogar den andra databas till rumsversionen.
  8. Matar ut data från båda via den ursprungliga Roomdatabasen med åtkomst till den bifogade andra databas via de ytterligare DAO-gränssnitten som inkluderar other.???? .

MainActivity.java

public class MainActivity extends AppCompatActivity {

    LoanPaymentDatabase mLPDB;
    Dao mLPDB_DAO;

    LoanPaymentDatabase mOtherDB;
    Dao mOtherDAO;
    Random rnd = new Random();

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

        mLPDB = Room.databaseBuilder(this,LoanPaymentDatabase.class,"mydb").allowMainThreadQueries().build();
        mLPDB_DAO = mLPDB.mDao();
        // Add some(2) AllUsers
        mLPDB_DAO.insertAllUsers(new AllUsers("Fred",5000,5));
        mLPDB_DAO.insertAllUsers(new AllUsers("Mary", 4000,6));

        // Add Some PaidUnpaid's for each AllUsers
        // Random amount with random paid or unpaid
        // This is just for demonstration and doesn't reflect what would typically be done
        List<AllUsers> allusers =  mLPDB_DAO.getAllAllUsers();
        for (AllUsers au: allusers) {
            int lc = rnd.nextInt(4) + 1;
            int month = 1;
            for (int i=0; i < lc; i++) {
                String paid = "Paid";
                if((rnd.nextInt(2) % 2) > 0 ) {
                    paid = "Unpaid";
                }
                mLPDB_DAO.insertPaidUnpaid(new PaidUnpaid(month++, paid, au.getAuid()));
            }
        }

        //Extract all AllUsersAndPaidUnpaid (i.e  each AllUsers with the related PaidUnpaid for the AllUsers)
        ArrayList<AllUsersAndPaidUnpaidsList> aupulist = new ArrayList<>();
        for (AllUsers au: allusers) {
            List<PaidUnpaid> pulist = mLPDB_DAO.getPaidUnpaidsForAllUsersId(au.getAuid());
            aupulist.add(new AllUsersAndPaidUnpaidsList(au,pulist));
        }

        // Output the results
        for (AllUsersAndPaidUnpaidsList aupu: aupulist) {
            aupu.outputToLog("INITALAUPU");
        }

        //Use separate openHelper rather than ATTACH
        mOtherDB = Room.databaseBuilder(this,LoanPaymentDatabase.class,OtherDatabaseHelper.DBNAME).allowMainThreadQueries().build();
        mOtherDAO = mOtherDB.mDao();
        ArrayList<AllUsersAndPaidUnpaidsList> otheraupulist = new ArrayList<>();
        for (AllUsers oau: mOtherDAO.getAllAllUsers() ) {
            otheraupulist.add(new AllUsersAndPaidUnpaidsList(oau,mOtherDAO.getPaidUnpaidsForAllUsersId(oau.getAuid())));
        }
        for (AllUsersAndPaidUnpaidsList aupu: otheraupulist) {
            aupu.outputToLog("ALTDBAUPU");
        }

        // User Attach
        SupportSQLiteDatabase main_sdb = mLPDB.getOpenHelper().getWritableDatabase();
        SupportSQLiteDatabase other_sdb = mOtherDB.getOpenHelper().getWritableDatabase();
        main_sdb.execSQL("ATTACH DATABASE '" + other_sdb.getPath() + "' AS other");
        ArrayList<AllUsersAndPaidUnpaidsList> attachaupulist = new ArrayList<>();
        for (AllUsers aau: mLPDB_DAO.getAllAllUsers()) {
            attachaupulist.add(new AllUsersAndPaidUnpaidsList(aau,mLPDB_DAO.getPaidUnpaidsForAllUsersId(aau.getAuid())));
        }
        for (AllUsers aauother: mLPDB_DAO.getOtherAllAllUsers()) {
            attachaupulist.add(new AllUsersAndPaidUnpaidsList(aauother,mLPDB_DAO.getOtherPaidUnpaidForAllUsersId(aauother.getAuid())));
        }
        for (AllUsersAndPaidUnpaidsList aupu: attachaupulist) {
            aupu.outputToLog("ATTACHEDAUPU");
        }

        mLPDB.close();
    }

    /*********
     *  For testing purposes - Populate the OTHER database to be used
     *********/
    private void manageOtherDatabase() {
        OtherDatabaseHelper mODBHlpr = new OtherDatabaseHelper(this);
        SQLiteDatabase db = mODBHlpr.getWritableDatabase();
        db.execSQL("PRAGMA user_version = 0");
        if (DatabaseUtils.queryNumEntries(db,OtherDatabaseHelper.ALLUSERS_TBL) > 0) {
            db.close();
            mODBHlpr.close();
            return;
        }
        db.beginTransaction();
        for (int i= 0; i < 5; i++) {
            long auid = mODBHlpr.insertAllUsers("AU" + String.valueOf(i),10000 + 1,5 + i);
            for(int ii = 0; ii < 5; ii++) {
                mODBHlpr.insertPaidUnpaid(ii,"Paid",auid);
            }
        }
        db.setTransactionSuccessful();
        db.endTransaction();
        db.close();
        mODBHlpr.close();
    }
}



  1. skicka LIMIT som parametrar till MySQL sproc

  2. Hur man installerar och säkrar MariaDB 10 i CentOS 6

  3. 3 sätt att ta reda på om en kolumn är en beräknad kolumn i SQL Server

  4. MySql-fel:1364 Fältet 'display_name' har inte standardvärde