I've been trying to get foreign keys working within my Android SQLite database. I have tried the following syntax but the foreign key is empty.
here is my databasehelper:
public static final String DATABASE_NAME ="popeye.db";
public static final int DATABASE_VERSION = 1;
public final Context context;
public static final String table12 = "users";
public DatabaseHelper(@Nullable Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
this.context = context;
}
@Override
public void onConfigure(SQLiteDatabase db) {
db.setForeignKeyConstraintsEnabled(true);
super.onConfigure(db);
}
@Override
public void onCreate(SQLiteDatabase db) {
String bookletinfo = "CREATE TABLE bookletinfo ( booklet_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, type VARCHAR NOT NULL, province VARCHAR NOT NULL, citymunicipality NOT NULL, barangay VARCHAR NOT NULL, address VARCHAR NOT NULL, respondent_name VARCHAR NOT NULL, household_head VARCHAR NOT NULL, hh_mem_count INTEGER NOT NULL, created_at DATETIME NOT NULL, updated_at TIMESTAMP)";
String demographiccharacteristics = "CREATE TABLE demographiccharacteristics (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, Q1 VARCHAR , Q2 VARCHAR , Q3 VARCHAR , Q4 INTEGER , Q5 DATE , Q6 VARCHAR , Q7 VARCHAR , Q8 VARCHAR , Q9 VARCHAR , Q10 VARCHAR , Q11 VARCHAR , Q12 VARCHAR , Q13 VARCHAR , Q14 VARCHAR , currentbrgy VARCHAR , created_at TIMESTAMP , updated_at TIMESTAMP, booklet_id INTEGER, FOREIGN KEY(booklet_id) REFERENCES bookletinfo(booklet_id))";
db.execSQL(bookletinfo);
db.execSQL(demographiccharacteristics);
}
@Override
public void onOpen(SQLiteDatabase db){
super.onOpen(db);
db.setForeignKeyConstraintsEnabled(true);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS bookletinfo");
db.execSQL("DROP TABLE IF EXISTS demographiccharacteristics");
onCreate(db);
}
public boolean addBooklet(String type1,String province,String municipality,String barangay, String address,String nameofrespondent, String householdhead, String householdtotal, String date,String updated_at) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put("type",type1);
contentValues.put("province",province);
contentValues.put("citymunicipality",municipality);
contentValues.put("barangay",barangay);
contentValues.put("address",address);
contentValues.put("respondent_name",nameofrespondent);
contentValues.put("household_head",householdhead);
contentValues.put("hh_mem_count", householdtotal);
contentValues.put("created_at", date);
contentValues.put("updated_at", updated_at);
db.insert("bookletinfo",null,contentValues);
return true;}
public boolean addDemographic(String etQ1,String etQ2,String etQ3,String etQ4,String etQ5,String etQ6,String etQ7,String etQ8,String etQ9,String etQ10,String etQ11,String etQ12,String etQ13,String etQ14, String etbrgy,String created_at,String updated_at) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put("Q1",etQ1);
contentValues.put("Q2",etQ2);
contentValues.put("Q3",etQ3);
contentValues.put("Q4",etQ4);
contentValues.put("Q5",etQ5);
contentValues.put("Q6",etQ6);
contentValues.put("Q7", etQ7);
contentValues.put("Q8",etQ8);
contentValues.put("Q9",etQ9);
contentValues.put("Q10",etQ10);
contentValues.put("Q11",etQ11);
contentValues.put("Q12",etQ12);
contentValues.put("Q13",etQ13);
contentValues.put("Q14", etQ14);
contentValues.put("currentbrgy",etbrgy);
contentValues.put("created_at",created_at);
contentValues.put("updated_at", updated_at);
db.insert("demographiccharacteristics",null,contentValues);
return true;
}
}
here is my code of taking and saving data to booklet info and it's working fine, the data is saved:
private static final String TAG = "home";
Button save, next, back, button;
EditText etprovince, etmunicipality, etbarangay, ethouseholdhead, etnameofrespondent, ettotalhouseholdmember, etaddress;
DatabaseHelper db;
private TextView mDisplayDate,tvdate2;
private DatePickerDialog.OnDateSetListener mDateSetListener;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
db = new DatabaseHelper(home.this);
etprovince = findViewById(R.id.province);
etmunicipality = findViewById(R.id.municipality);
etbarangay = findViewById(R.id.barangay);
ethouseholdhead = findViewById(R.id.q2);
etnameofrespondent = findViewById(R.id.respondentname);
ettotalhouseholdmember = findViewById(R.id.totalmember);
etaddress = findViewById(R.id.address);
tvdate2=findViewById(R.id.q5);
Spinner type = (Spinner) findViewById(R.id.ettype);
ArrayAdapter<String> myAdapter = new ArrayAdapter<String>(home.this,
android.R.layout.simple_list_item_1, getResources().getStringArray(R.array.type));
myAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
type.setAdapter(myAdapter);
save = (Button) findViewById(R.id.save);
save.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String province = etprovince.getText().toString();
String municipality = etmunicipality.getText().toString();
String barangay = etbarangay.getText().toString();
String householdhead = ethouseholdhead.getText().toString();
String nameofrespondent = etnameofrespondent.getText().toString();
String householdtotal = ettotalhouseholdmember.getText().toString();
String address = etaddress.getText().toString();
String type1 = type.getSelectedItem().toString();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date = sdf.format(new Date());
String updated_at = "";
if (db.addBooklet(type1,province, municipality, barangay,address,nameofrespondent,householdhead, householdtotal,date,updated_at)) {
Toast.makeText(getApplicationContext(), "Data Inserted", Toast.LENGTH_SHORT).show();
Intent registerIntent = new Intent(home.this, Survey2.class);
startActivity(registerIntent);
} else {
Toast.makeText(getApplicationContext(), "error", Toast.LENGTH_SHORT).show();
}
}
});
back = (Button) findViewById(R.id.back);
back.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent registerIntent = new Intent(home.this, menu.class);
startActivity(registerIntent);
}
});
}
and here is another adding and saving data and it's working. but my booklet_id is empty everytime i save a data. what i want to do is booklet_idis automatically input and the "booklet_id INTEGER, FOREIGN KEY(booklet_id) REFERENCES bookletinfo(booklet_id)" is not working. i need help
private static final String TAG = "Survey2";
private TextView mDisplayDate;
private DatePickerDialog.OnDateSetListener mDateSetListener;
DatabaseHelper db;
Button next,save;
TextView tvDate;
EditText Q1,Q4,brgy,Q6,Q7,Q9,Q10,Q14;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_survey2);
db = new DatabaseHelper(Survey2.this);
brgy =(EditText) findViewById(R.id.brgy);
Q1 = (EditText)findViewById(R.id.q1);
Q4 = (EditText)findViewById(R.id.q4);
Q14 = (EditText)findViewById(R.id.q14);
Q6 = (EditText)findViewById(R.id.q6);
Q7 = (EditText)findViewById(R.id.q7);
Q9 = (EditText)findViewById(R.id.q9);
Q10 = (EditText)findViewById(R.id.q10);
tvDate=findViewById(R.id.q5);
//household head spinner
Spinner relationship = (Spinner) findViewById(R.id.q2);
ArrayAdapter<String> myAdapter = new ArrayAdapter<String>(Survey2.this,
android.R.layout.simple_list_item_1, getResources().getStringArray(R.array.relationship));
myAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
relationship.setAdapter(myAdapter);
//Gender spinner
Spinner SEX = (Spinner) findViewById(R.id.q3);
ArrayAdapter<String> sex = new ArrayAdapter<String>(Survey2.this,
android.R.layout.simple_list_item_1, getResources().getStringArray(R.array.SEX));
sex.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
SEX.setAdapter(sex);
//marital spinner
Spinner marital1 = (Spinner) findViewById(R.id.q8);
ArrayAdapter<String> marital = new ArrayAdapter<String>(Survey2.this,
android.R.layout.simple_list_item_1, getResources().getStringArray(R.array.marital));
marital.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
marital1.setAdapter(marital);
//education spinner
Spinner Education = (Spinner) findViewById(R.id.q11);
ArrayAdapter<String> education = new ArrayAdapter<String>(Survey2.this,
android.R.layout.simple_list_item_1, getResources().getStringArray(R.array.education));
education.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
Education.setAdapter(education);
//enroled? spinner
Spinner Enrolled = (Spinner) findViewById(R.id.q12);
ArrayAdapter<String> enrolled = new ArrayAdapter<String>(Survey2.this,
android.R.layout.simple_list_item_1, getResources().getStringArray(R.array.currentEnrolled));
enrolled.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
Enrolled.setAdapter(enrolled);
//spinner educ level
Spinner level = (Spinner) findViewById(R.id.q13);
ArrayAdapter<String> Level = new ArrayAdapter<String>(Survey2.this,
android.R.layout.simple_list_item_1, getResources().getStringArray(R.array.level));
Level.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
level.setAdapter(Level);
mDisplayDate = (TextView)findViewById(R.id.q5);
mDisplayDate.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Calendar cal2 = Calendar.getInstance();
int y2=cal2.get(Calendar.YEAR);
int m2=cal2.get(Calendar.MONTH);
int d2=cal2.get(Calendar.DAY_OF_MONTH);
DatePickerDialog dialog2 = new DatePickerDialog(Survey2.this,
android.R.style.Theme_Holo_Light_Dialog_MinWidth,mDateSetListener,y2,m2,d2);
dialog2.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
dialog2.show();
}
});
mDateSetListener =new DatePickerDialog.OnDateSetListener() {
@Override
public void onDateSet(DatePicker datePicker, int y2, int m2, int d2) {
m2 = m2+1;
Log.d(TAG, "onDateSet: yyy/mm/dd" + y2 + "-" + m2 + "-" + d2 );
String date2 = y2 + "-" + m2 + "-" +d2;
mDisplayDate.setText(date2);
}
};
save = (Button)findViewById(R.id.save);
save.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String etQ1 = Q1.getText().toString();
String etQ2 = relationship.getSelectedItem().toString();
String etQ3 = SEX.getSelectedItem().toString();
String etQ4 = Q4.getText().toString();
String etQ5= tvDate.getText().toString();
String etQ6 = Q6.getText().toString();
String etQ7 = Q7.getText().toString();
String etQ8 = marital1.getSelectedItem().toString();
String etQ9 = Q9.getText().toString();
String etQ10 =Q10.getText().toString();
String etQ11 = Education.getSelectedItem().toString();
String etbrgy = brgy.getText().toString();
String etQ12 = Enrolled.getSelectedItem().toString();
String etQ13 = level.getSelectedItem().toString();
String etQ14 = Q14.getText().toString();
String updated_at = "";
//current date
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String created_at = sdf.format(new Date());
if (db.addDemographic(etQ1,etQ2,etQ3,etQ4,etQ5,etQ6,etQ7,etQ8,etQ9,etQ10,etQ11,etQ12,etQ13,etQ14,etbrgy,created_at,updated_at)) {
Toast.makeText(getApplicationContext(), "Data Inserted", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getApplicationContext(), "error", Toast.LENGTH_SHORT).show();
}
}
});
}
It appears that you may be think that SQLite automatically associates children with parents when a Foreign Key clause is coded. It does not and can not.
What a Foreign Key clause does is add a constraint (a rule) that says that the value of the column in the child MUST be a value that exists in the specified column in one of the rows of the parent table. If this rule is broken then a conflict occurs, thus indicating a breach of referential integrity (aka a parentless child (orphans)).
It should be understood that the Foreign Key clause is not the same as the term Foreign Key used when describing databases. For a foreign key to exists there is no requirement for a Foreign key clause. Rather the Foreign Key clause supports the existence of the foreign key.
You have to determine what can be inserted.
First I would suggest changing methods addBooklet and addDemographic from returning a boolean to return a long and returning the result of the insert.
if (addBooklet(....) > 0)
to be true if the row was inserted.You also need to allow the booklet_id to be provided when inserting a Demographic and for the provideed value to be inserted (added to the ContentValues)
So the methods in the DatabaseHelper could be changed to :-
public /*boolean*/ long addBooklet(String type1,String province,String municipality,String barangay, String address,String nameofrespondent, String householdhead, String householdtotal, String date,String updated_at) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put("type",type1);
contentValues.put("province",province);
contentValues.put("citymunicipality",municipality);
contentValues.put("barangay",barangay);
contentValues.put("address",address);
contentValues.put("respondent_name",nameofrespondent);
contentValues.put("household_head",householdhead);
contentValues.put("hh_mem_count", householdtotal);
contentValues.put("created_at", date);
contentValues.put("updated_at", updated_at);
return db.insert("bookletinfo",null,contentValues);
/*return true;*/}
public /*boolean*/ long addDemographic(/* ADDED >>>>> */long booklet_id,String etQ1,String etQ2,String etQ3,String etQ4,String etQ5,String etQ6,String etQ7,String etQ8,String etQ9,String etQ10,String etQ11,String etQ12,String etQ13,String etQ14, String etbrgy,String created_at,String updated_at) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put("booklet_id",booklet_id); /*<<<<< ADDED */
contentValues.put("Q1",etQ1);
contentValues.put("Q2",etQ2);
contentValues.put("Q3",etQ3);
contentValues.put("Q4",etQ4);
contentValues.put("Q5",etQ5);
contentValues.put("Q6",etQ6);
contentValues.put("Q7", etQ7);
contentValues.put("Q8",etQ8);
contentValues.put("Q9",etQ9);
contentValues.put("Q10",etQ10);
contentValues.put("Q11",etQ11);
contentValues.put("Q12",etQ12);
contentValues.put("Q13",etQ13);
contentValues.put("Q14", etQ14);
contentValues.put("currentbrgy",etbrgy);
contentValues.put("created_at",created_at);
contentValues.put("updated_at", updated_at);
return db.insert("demographiccharacteristics",null,contentValues);
/*return true;*/
}
You now have a means of obtaining the booklet_id when adding a new Booklet to so this can be used when adding a Demographic child.
eg :-
public class MainActivity extends AppCompatActivity {
DatabaseHelper db;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
db = new DatabaseHelper(this);
long currentBooklet = db.addBooklet("Type1","Province1","municipality1","barangay1","address1","name1","househol1","1","2021-01-01","2021-01-01");
if (currentBooklet > 0) {
db.addDemographic(currentBooklet,"Demo1","Q2","Q3","Q4","Q5","Q6","Q7","Q8","Q9","Q10","Q11","Q12","Q13","Q14","etbrgy","2021-01-01","202-01-01");
db.addDemographic(currentBooklet,"Demo2","Q2","Q3","Q4","Q5","Q6","Q7","Q8","Q9","Q10","Q11","Q12","Q13","Q14","etbrgy","2021-01-01","202-01-01");
}
}
}
This resulting in the following data in the database :-
The bookletinfo table (only partial data displayed) :-
The demographiccharecteristics table :-
ie the two rows have been inserted as the was no Foreign Key conflict.
Now if you attempted
db.addDemographic(10,"Demo2","Q2","Q3","Q4","Q5","Q6","Q7","Q8","Q9","Q10","Q11","Q12","Q13","Q14","etbrgy","2021-01-01","202-01-01");
ie 10 is not a value in the booklet_id column of any of the rows (there is only the 1 row and the booklet_id is 1) * then a Foreign Key conflict will occur. However the convenience insert method traps/catches the underlying exception (the insertOrThrow
method would not) and returns -1 as no row is inserted.
If you look at the log you can see that exceptions are raised but caught. eg the lone of code above result in the log including :-
2021-10-30 09:19:43.455 22029-22029/a.a.so69769911javasqlitefk E/SQLiteDatabase: Error inserting Q1=Demo2 Q2=Q2 Q3=Q3 Q4=Q4 Q5=Q5 Q6=Q6 Q7=Q7 Q8=Q8 currentbrgy=etbrgy Q9=Q9 created_at=2021-01-01 Q11=Q11 Q10=Q10 Q13=Q13 Q12=Q12 updated_at=202-01-01 Q14=Q14 booklet_id=10
android.database.sqlite.SQLiteConstraintException: FOREIGN KEY constraint failed (code 787 SQLITE_CONSTRAINT_FOREIGNKEY)
at android.database.sqlite.SQLiteConnection.nativeExecuteForLastInsertedRowId(Native Method)
at android.database.sqlite.SQLiteConnection.executeForLastInsertedRowId(SQLiteConnection.java:796)
at android.database.sqlite.SQLiteSession.executeForLastInsertedRowId(SQLiteSession.java:788)
at android.database.sqlite.SQLiteStatement.executeInsert(SQLiteStatement.java:86)
at android.database.sqlite.SQLiteDatabase.insertWithOnConflict(SQLiteDatabase.java:1564)
at android.database.sqlite.SQLiteDatabase.insert(SQLiteDatabase.java:1433)
at a.a.so69769911javasqlitefk.DatabaseHelper.addDemographic(DatabaseHelper.java:120)
at a.a.so69769911javasqlitefk.MainActivity.onCreate(MainActivity.java:20)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.