Возможно, вы не хотите иметь эту строку: -
args.put(ID_MOVIE, movieFavorite.getId());
в методе insertMovie .
Без строки идентификатор будет сгенерировано автоматически (1, затем 2, затем 3 (вероятно)).
Если вы включите вышеприведенную строку, то будет сделана попытка вставить НО , если значение уже используется в этом столбце, в других строках, тогда вы получите конфликт ограничений UNIQUE,То есть первичные ключи должны быть УНИКАЛЬНЫМИ и, следовательно, даже без кодирования УНИКАЛЬНЫЕ они являются такими, как если бы УНИКАЛЬНО был закодирован (т.е. подразумевается ограничение УНИКАЛЬНОЕ).
Примечание;вам, скорее всего, не нужно AUTOINCREMENT , + " (%s INTEGER PRIMARY KEY," +
все равно будет автоматически генерировать id , но будет более эффективным.Согласно: -
Ключевое слово AUTOINCREMENT накладывает дополнительные ресурсы процессора, памяти, дискового пространства и дискового ввода-вывода, и их следует избегать, если в этом нет особой необходимости.Обычно это не требуется.
Автоинкремент SQLite
Согласно комментарию: -
Если args.put (ID_MOVIE, movieFavorite.getId ());не добавляется, тогда данные будут дублироваться
вот пример: -
DbHelper.java
public class DbHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "movielist";
private static final int DATABASE_VERSION = 1;
private static final String DATABASE_TABLE = DbContract.TABLE_MOVIE;
private static final String SQL_CREATE_TABLE_MOVIE_FAV = String.format("CREATE TABLE %s"
+ " (%s INTEGER PRIMARY KEY AUTOINCREMENT," +
" %s TEXT NOT NULL," +
" %s TEXT NOT NULL," +
" %s TEXT NOT NULL," +
" %s TEXT NOT NULL," +
" %s TEXT NOT NULL)",
DATABASE_TABLE,
DbContract.MovieListFavorite.MOVIE_ID,
DbContract.MovieListFavorite.MOVIE_TITLE,
DbContract.MovieListFavorite.MOVIE_OVERVIEW,
DbContract.MovieListFavorite.MOVIE_RELEASE_DATE,
DbContract.MovieListFavorite.MOVIE_PHOTO,
DbContract.MovieListFavorite.MOVIE_VOTE_AVERAGE
);
SQLiteDatabase sqLiteDatabase;
public DbHelper(@Nullable Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
sqLiteDatabase = this.getWritableDatabase();
}
public long insertMovie(MovieFav movieFavorite) {
ContentValues args = new ContentValues();
args.put(DbContract.MovieListFavorite.MOVIE_TITLE, movieFavorite.getTitle());
//<<<<<<<<<< ID REMOVED >>>>>>>>>>
args.put(DbContract.MovieListFavorite.MOVIE_OVERVIEW, movieFavorite.getOverview());
args.put(DbContract.MovieListFavorite.MOVIE_RELEASE_DATE, movieFavorite.getRelease_date());
args.put(DbContract.MovieListFavorite.MOVIE_VOTE_AVERAGE, movieFavorite.getVote_average());
args.put(DbContract.MovieListFavorite.MOVIE_PHOTO, movieFavorite.getPoster_path());
return sqLiteDatabase.insert(DATABASE_TABLE, null, args);
}
//<<<<<<<<<< ADDED FOR THE DEMO TO LIST MOVIES WITH THE ID >>>>>>>>>>
public void logAllMovies() {
Cursor csr = sqLiteDatabase.query(DATABASE_TABLE,null,null,null,null,null,null);
while (csr.moveToNext()) {
Log.d("MOVIELIST",
"Title is " + csr.getString(csr.getColumnIndex(DbContract.MovieListFavorite.MOVIE_TITLE)) +
"\n\tID is " + csr.getString(csr.getColumnIndex(DbContract.MovieListFavorite.MOVIE_ID)) +
"\n\tOverview is \n\t\t" + csr.getString(csr.getColumnIndex(DbContract.MovieListFavorite.MOVIE_OVERVIEW))
/* and so on */
);
}
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(SQL_CREATE_TABLE_MOVIE_FAV);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
//<<<<<<<<<< ADDED to complete (may be different) >>>>>>>>>>
private class DbContract {
private static final String TABLE_MOVIE = "movie";
private class MovieListFavorite {
private static final String MOVIE_ID = BaseColumns._ID;
private static final String MOVIE_TITLE = "title";
private static final String MOVIE_OVERVIEW = "overview";
private static final String MOVIE_RELEASE_DATE = "release_date";
private static final String MOVIE_PHOTO = "photo";
private static final String MOVIE_VOTE_AVERAGE = "vote_average";
}
}
}
MovieFav.java
public class MovieFav {
private long id;
private String Title;
private String Overview;
private String Release_date;
private String Vote_average;
private String Poster_path;
public MovieFav() {
}
public MovieFav(String title, String overview, String release_date, String vote_average, String poster_path) {
this.Title = title;
this.Overview = overview;
this.Release_date = release_date;
this.Vote_average = vote_average;
this.Poster_path = poster_path;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getTitle() {
return Title;
}
public void setTitle(String title) {
Title = title;
}
public String getOverview() {
return Overview;
}
public void setOverview(String overview) {
Overview = overview;
}
public String getRelease_date() {
return Release_date;
}
public void setRelease_date(String release_date) {
Release_date = release_date;
}
public String getVote_average() {
return Vote_average;
}
public void setVote_average(String vote_average) {
Vote_average = vote_average;
}
public String getPoster_path() {
return Poster_path;
}
public void setPoster_path(String poster_path) {
Poster_path = poster_path;
}
}
Код в Деятельности
public class MainActivity extends AppCompatActivity {
DbHelper mMyDBHlpr;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mMyDBHlpr = new DbHelper(this); //Instantiate Database Helper
// Add some Movies WITHOUT specifying ID
mMyDBHlpr.insertMovie(new MovieFav("Gone with the wind","It blows","2019-01-01","medium","//posters/movies/gwtw"));
mMyDBHlpr.insertMovie(new MovieFav("The Magnificent Seven","Magnificent","2019-10-01","medium","//posters/movies/tms"));
mMyDBHlpr.insertMovie(new MovieFav("The Lord of the Rings","I'll ring you about this one","2015-12-01","great","//posters/movies/lotrp1"));
mMyDBHlpr.insertMovie(new MovieFav("War of the Worlds","Alien to me","2010-01-01","ok","//posters/movies/wotw"));
// Output Movies information to the log INCLUDING ID
mMyDBHlpr.logAllMovies();
}
Результат в Журнале: -
2019-09-28 19:51:52.242 7088-7088/aso.asoinmemorysbtofiledb D/MOVIELIST: Title is Gone with the wind
ID is 1
Overview is
It blows
2019-09-28 19:51:52.243 7088-7088/aso.asoinmemorysbtofiledb D/MOVIELIST: Title is The Magnificent Seven
ID is 2
Overview is
Magnificent
2019-09-28 19:51:52.243 7088-7088/aso.asoinmemorysbtofiledb D/MOVIELIST: Title is The Lord of the Rings
ID is 3
Overview is
I'll ring you about this one
2019-09-28 19:51:52.243 7088-7088/aso.asoinmemorysbtofiledb D/MOVIELIST: Title is War of the Worlds
ID is 4
Overview is
Alien to me
Поскольку вышеизложенное всегда пытается добавить 4 строки, если выполняется второй раз, то: -
2019-09-28 20:00:52.454 7188-7188/aso.asoinmemorysbtofiledb D/MOVIELIST: Title is Gone with the wind
ID is 1
Overview is
It blows
2019-09-28 20:00:52.454 7188-7188/aso.asoinmemorysbtofiledb D/MOVIELIST: Title is The Magnificent Seven
ID is 2
Overview is
Magnificent
2019-09-28 20:00:52.454 7188-7188/aso.asoinmemorysbtofiledb D/MOVIELIST: Title is The Lord of the Rings
ID is 3
Overview is
I'll ring you about this one
2019-09-28 20:00:52.454 7188-7188/aso.asoinmemorysbtofiledb D/MOVIELIST: Title is War of the Worlds
ID is 4
Overview is
Alien to me
2019-09-28 20:00:52.454 7188-7188/aso.asoinmemorysbtofiledb D/MOVIELIST: Title is Gone with the wind
ID is 5
Overview is
It blows
2019-09-28 20:00:52.454 7188-7188/aso.asoinmemorysbtofiledb D/MOVIELIST: Title is The Magnificent Seven
ID is 6
Overview is
Magnificent
2019-09-28 20:00:52.454 7188-7188/aso.asoinmemorysbtofiledb D/MOVIELIST: Title is The Lord of the Rings
ID is 7
Overview is
I'll ring you about this one
2019-09-28 20:00:52.455 7188-7188/aso.asoinmemorysbtofiledb D/MOVIELIST: Title is War of the Worlds
ID is 8
Overview is
Alien to me
т.е. были добавлены те же строки, НО с другими идентификаторами (на этот раз 5-8)
Нет дублирующихся фильмов
Если вы хотите не дублировать данные, напримервесь фильм, так что 5-8 не будут добавлены, тогда вы можете создать уникальное ограничение, соответствующее данным, которые вы не хотите дублировать. id никогда не будет дублироваться, это не может быть и бесполезно с точки зрения данных, с точки зрения информации о фильме (идентификатор очень полезен с точки зрения базы данных).
Предполагая, что вы никогда не хотите, чтобы фильм был добавлен, если уже есть фильм с тем же названием и той же датой выпуска, то вы можете сделать комбинацию названия фильма и даты выпуска фильма УНИКАЛЬНОЙ.
например, для вышеупомянутого, тогда ваш код для создания таблицы может быть (см. комментарии): -
private static final String DATABASE_NAME = "movielist";
private static final int DATABASE_VERSION = 1;
private static final String DATABASE_TABLE = DbContract.TABLE_MOVIE;
private static final String SQL_CREATE_TABLE_MOVIE_FAV = String.format("CREATE TABLE %s"
+ " (%s INTEGER PRIMARY KEY AUTOINCREMENT," +
" %s TEXT NOT NULL," +
" %s TEXT NOT NULL," +
" %s TEXT NOT NULL," +
" %s TEXT NOT NULL," +
" %s TEXT NOT NULL" + //<<<<<<<<<< REMOVED CLOSING PARENTHESIS
/* ADDED the UNQIUE CONSTRAINT ON THE Title and release date */
", UNIQUE ("
+ DbContract.MovieListFavorite.MOVIE_TITLE +
"," + DbContract.MovieListFavorite.MOVIE_RELEASE_DATE
+ ")" + // END Of THE UNIQUE CONSTRAINT
")", //<<<<<<<<<< END OF CHANGES FOR ADDING UNIQUE constraint
/**
* NOTE AS THE SCHEMA HAS CHANGED THE DATABASE NEEDS TO BE DELETED (altering is possible but harder)
* THEREFORE TO INTRODUCE CHANGES >>>>>>>>>>UNINSTALL THE APP AND THEN RERUN<<<<<<<<<<.
*/
DATABASE_TABLE,
DbContract.MovieListFavorite.MOVIE_ID,
DbContract.MovieListFavorite.MOVIE_TITLE,
DbContract.MovieListFavorite.MOVIE_OVERVIEW,
DbContract.MovieListFavorite.MOVIE_RELEASE_DATE,
DbContract.MovieListFavorite.MOVIE_PHOTO,
DbContract.MovieListFavorite.MOVIE_VOTE_AVERAGE
);
Ошибка (не является таковой)
Что касается сообщения, оноявляется перехваченным исключением, оно не приводит к сбою и сообщаемые строки не добавляются.
Если вы хотите обойти отчеты в журнале, вам придется использовать альтернативный метод, которыйвлечет за собой генерацию SQL вставки, который использует INSERT OR IGNORE INTO the_table (a_comma_separated_list_of_the_columns_for_which_data_is_supplied) VALUES(a_comma_separated_list_of_values)
(значения, которые составляют предложение, описывают значения в целом, это не специальное значение, которое будет использоваться).
В шоrt метод вставки может быть: -
public long insertMovieAlternative(MovieFav movieFavorite) {
String insertSQL = "INSERT OR IGNORE INTO " + DATABASE_TABLE +
"(" +
DbContract.MovieListFavorite.MOVIE_TITLE + "," +
DbContract.MovieListFavorite.MOVIE_OVERVIEW + "," +
DbContract.MovieListFavorite.MOVIE_RELEASE_DATE + "," +
DbContract.MovieListFavorite.MOVIE_VOTE_AVERAGE + "," +
DbContract.MovieListFavorite.MOVIE_PHOTO +
") VALUES (?,?,?,?,?)";
SQLiteStatement sqlstmnt = sqLiteDatabase.compileStatement(insertSQL);
sqlstmnt.bindAllArgsAsStrings(new String[]{
movieFavorite.getTitle(),
movieFavorite.getOverview(),
movieFavorite.getRelease_date(),
movieFavorite.getVote_average(),
movieFavorite.getPoster_path()
});
Log.d("ALTINSERTSQL",sqlstmnt.toString());
return sqlstmnt.executeInsert();
}
ПРИМЕЧАНИЕ: строка Log.d("ALTINSERTSQL",sqlstmnt.toString());
не нужна, она была добавлена, чтобы показать, что генерируется SQL, как передается в SQLite, например
INSERT OR IGNORE INTO movie(title,overview,release_date,vote_average,photo) VALUES (?,?,?,?,?)
Символы? Связаны API-интерфейсом SQLite (аналогично использованию String.format) и, следовательно,использование bindAllArgsAsStrings , чтобы позволить SQlite заменить каждый?с соответствующим значением.Это предотвращает SQLInjection.
Примите во внимание вышеизложенное и используйте: -
mMyDBHlpr = new DbHelper(this); //Instantiate Database Helper
// Add some Movies WITHOUT specifying ID
mMyDBHlpr.insertMovie(new MovieFav("Gone with the wind","It blows","2019-01-01","medium","//posters/movies/gwtw"));
mMyDBHlpr.insertMovie(new MovieFav("The Magnificent Seven","Magnificent","2019-10-01","medium","//posters/movies/tms"));
mMyDBHlpr.insertMovie(new MovieFav("The Lord of the Rings","I'll ring you about this one","2015-12-01","great","//posters/movies/lotrp1"));
mMyDBHlpr.insertMovie(new MovieFav("War of the Worlds","Alien to me","2010-01-01","ok","//posters/movies/wotw"));
mMyDBHlpr.insertMovieAlternative(new MovieFav("Gone with the wind","It blows","2019-01-01","medium","//posters/movies/gwtw"));
mMyDBHlpr.insertMovieAlternative(new MovieFav("The Magnificent Seven","Magnificent","2019-10-01","medium","//posters/movies/tms"));
mMyDBHlpr.insertMovieAlternative(new MovieFav("The Lord of the Rings","I'll ring you about this one","2015-12-01","great","//posters/movies/lotrp1"));
mMyDBHlpr.insertMovieAlternative(new MovieFav("War of the Worlds","Alien to me","2010-01-01","ok","//posters/movies/wotw"));
// Output Movies information to the log INCLUDING ID
mMyDBHlpr.logAllMovies();
Попытка добавить тот же набор фильмов, НО выигран второй лот; t из-задобавлено ограничение UNIQUE для сочетания даты выпуска фильма Movie Title Movie Release, НО в журнале нет сообщений об исключениях (исключений нет, потому что INSERT OR IGNORE действует как noop (ничего не делать), если возникает конфликт).
Лог вместо этого будет: -
2019-09-28 20:52:06.304 D/ALTINSERTSQL: SQLiteProgram: INSERT OR IGNORE INTO movie(title,overview,release_date,vote_average,photo) VALUES (?,?,?,?,?)
2019-09-28 20:52:06.305 I/chatty: uid=10419(aso.asoinmemorysbtofiledb) identical 2 lines
2019-09-28 20:52:06.306 D/ALTINSERTSQL: SQLiteProgram: INSERT OR IGNORE INTO movie(title,overview,release_date,vote_average,photo) VALUES (?,?,?,?,?)
2019-09-28 20:52:06.307 D/MOVIELIST: Title is Gone with the wind
ID is 1
Overview is
It blows
2019-09-28 20:52:06.307 D/MOVIELIST: Title is The Magnificent Seven
ID is 2
Overview is
Magnificent
2019-09-28 20:52:06.307 D/MOVIELIST: Title is The Lord of the Rings
ID is 3
Overview is
I'll ring you about this one
2019-09-28 20:52:06.307 D/MOVIELIST: Title is War of the Worlds
ID is 4
Overview is
Alien to me