Сохранение нескольких Arraylist в базе данных комнаты - лучший способ сделать это? - PullRequest
0 голосов
/ 24 ноября 2018

Справочная информация: Я пытаюсь построить Deckbuilder для карточной игры.Различные колоды основаны на одном Arraylists, которые я хочу сохранить на месте.Это означает, что вы можете создать свою колоду, а затем я хочу, чтобы вы смогли ее сохранить, а затем создать новую колоду, чтобы сохранить ее снова ... -> Это дает несколько Arraylists, которые я хочу сохранить втот же класс.

Вопрос: Каков наилучший способ хранения Arraylists в комнате, зная, что я хочу, чтобы не только один Arraylist пришел?

Из того, что я знаю сейчас, это то, что мне нужно создать класс сущностей, который, в основном, создаст мне одну (?) Таблицу, в которой мне придется сохранять Arraylists друг за другом?

Есть ли лучший способделать это.

Бонус: Мне бы очень понравился базовый пример того, как это сделать, так как это кажется мне очень трудным для достижения.

Спасибоочень много!

Редактировать:

Пример кода

Итак, что я реализовал с помощью базовой линии из вашего примера кода:

  1. Я создал класс SaveDeck, который должен быть в состоянии Сохранить колоду с заданным именем колоды :: -

    @ Открытый класс сущности SaveDeck реализует Serializable {@PrimaryKey (autoGenerate = true) private int _id;

    public SaveDeck(int _id, String deckName, int cardImage, int typeImage, Integer cardCost, String cardName, Integer cardNumber) {
        this._id = _id;
        DeckName = deckName;
        CardImage = cardImage;
        TypeImage = typeImage;
        CardCost = cardCost;
        CardName = cardName;
        CardNumber = cardNumber;
    }
    
    @ColumnInfo(name = "DeckName")
    private String DeckName;
    
    @ColumnInfo(name = "CardImage")
    private int CardImage;
    
    @ColumnInfo(name = "TypeImage")
    private int TypeImage;
    
    @ColumnInfo(name = "CardCost")
    private Integer CardCost;
    
    @ColumnInfo(name = "CardName")
    private String CardName;
    
    @ColumnInfo(name = "CardNumber")
    private Integer CardNumber;
    

    }

  2. Я создал класс Dao следующим образом: -

    @ открытый интерфейс Dao DeckBuilderDao {

    @Insert(onConflict = OnConflictStrategy.IGNORE)
    public long[] insertCards(SaveDeck... saveDecks);
    
    @Insert(onConflict = OnConflictStrategy.IGNORE)
    public long insertCard(SaveDeck saveDecks);
    
    @Update
    public int updateCardBaseEntries(SaveDeck... saveDecks);
    
    @Update
    public int updateCardBaseEntry(SaveDeck saveDecks);
    
    @Delete
    public int deleteCardBaseEntried(SaveDeck... saveDecks);
    
    @Delete
    public int deleteCardBaseEntry(SaveDeck saveDecks);
    
    @Query("SELECT * FROM SaveDeck")
    public SaveDeck[] getAllDecks();
    
    //probably I do not need the getAllDecks Query. Right now I only need the following one:
    @Query("SELECT * FROM SaveDeck WHERE DeckName = :NameOfDeck ORDER  BY DeckName, CardName")
    public SaveDeck getOneDeck(String NameOfDeck);
    

    }

  3. Кроме того, создан класс DataBase:

    @ Database (entity = {SaveDeck.class}, version = 1) открытый абстрактный класс SaveDecksDataBase extends RoomDatabase {public abstract DeckBuilderDao deckBuilderDao ();}

  4. Наконец-то попытался создать настройку в моем соответствующем фрагменте, вот где я борюсь:: -

    public class review_fragment extends Fragment {

    private List<TransferDeck> mTransferDeck = DataHolder.getInstance().savedDecklistTransfer;
    SaveDecksDataBase mSavedDecksDB;
    Cursor mCursor;
    
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    //return super.onCreateView(inflater, container, savedInstanceState);
        View view = inflater.inflate(R.layout.review_fragment, container, false);
    
        /*Introduce Cards Recycler*/
    
        RecyclerView rvCards = view.findViewById(R.id.rv_review_cardlist);
        rvCards.setLayoutManager(new GridLayoutManager(getActivity(), 5));
        review_RViewAdapter_Cards adapterCards = new review_RViewAdapter_Cards(getContext(), mTransferDeck);
        rvCards.setAdapter(adapterCards);
    
    
    
        /*Init Room database*/
        mSavedDecksDB = Room.databaseBuilder(getActivity(),SaveDecksDataBase.class,"SavedDecksDB.db").build();
        populateDB(mTransferDeck);
    
    
    
    
    
        return view;
    }
    
    private void populateDB(final List<TransferDeck> mTransferDeck) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                List<SaveDeck> mSaveDeck = new ArrayList<>();
                for(int i = 0; i<mTransferDeck.size(); i++){
                    mSaveDeck.add(new SaveDeck(i, "FirstSavedDeck", mTransferDeck.get(i).getCardImage() ,mTransferDeck.get(i).getTypeImage(), mTransferDeck.get(i).getCost(), mTransferDeck.get(i).getName(), mTransferDeck.get(i).getNumber()));
                }
                mSavedDecksDB.deckBuilderDao().insertCards(mSaveDeck);
    
            }
        }).start();
    }
    

    }

Поэтому сейчас я не знаю, как правильно добавить новые экземпляры в мой класс SaveDeck.Я привык использовать Arraylists с конструкторами. Поэтому я попробовал это так.Не могли бы вы взглянуть на это и помочь мне, пожалуйста?

1 Ответ

0 голосов
/ 25 ноября 2018

Каков наилучший способ хранения Arraylists в Комнате, зная, что я хочу, чтобы не только один Arraylist приходил?

Возможно, нет лучшего пути.

ArrayList не просто появляются, данные и структура элемента (если существует несколько значений на элемент) откуда-то, то есть они являются просто контейнерами, а не постоянными контейнерами сгруппированных данных.Поскольку конечный результат, по-видимому, представляет собой устойчивые структурированные наборы данных, вероятно, было бы проще в первую очередь использовать базу данных.

Я пытаюсь построить Deckbuilder для карточной игры.Различные колоды основаны на одном Arraylists, которые я хочу сохранить локально.

Звучит так, будто это база карт, то есть карт, доступных для игры.Похоже, вам нужна таблица в базе данных для карт .

Это означает, что вы можете создать свою колоду, и тогда я хочу, чтобы вы смогли ее сохранить, изатем создайте новую колоду,

Звучит так, как будто вам нужна таблица в базе данных для колод и что в колоде может быть список карт.Так сколько карт?10, 20, 3000?Хорошо, если вы используете возможности отношений Realtional Database Manager (который SQLite и, следовательно, Room (так как последний является абстрактным слоем над SQLite)).Таким образом, вполне вероятно, что то, что известно как таблица сопоставления (ссылки, отношения и другие имена для одной и той же вещи).

Это в первую очередь хранит отношения, которые состоят из столбца, который может идентифицировать одну часть отношения идругой столбец, который может идентифицировать другую часть.Примените это к вашему случаю, когда DECK будет иметь отношение к нескольким картам, CARD может появиться в нескольких DECK.Это много-много отношений, которые обслуживает таблица сопоставления.Поэтому вам, вероятно, понадобится таблица mapping .

В качестве основы для дальнейших объяснений предполагается, что речь идет об игральных картах (Ace of Spades, Queen of Hearts и так далее).

Итак, нам нужны три таблицы: таблица Card , таблица Deck и таблица, которая отображает карты в колоды (и, следовательно, наоборот), Card_Deck_MapТаблица .

Таблица Card для простоты будет иметь один столбец для имя карты .Таблицы Deck будут иметь один столбец для deckname . Для эффективности будет использован идентификатор, который является псевдонимом специального столбца rowid .Таким образом, в каждой из приведенных выше таблиц будет дополнительный столбец, который будет называться _id (при названии столбца _id это может быть полезно для Android).

Это будетПредполагается, что вы не хотите, чтобы имя карты или название колоды дублировались, и поэтому будут применены УНИКАЛЬНЫЕ ограничения, которые не позволят дублировать имена.

Чтобы сократить все, вот как этоможет выглядеть в SQL (что, в конечном счете, делает большинство операций по хранению, обработке и извлечению данных): -

-- Delete the tables if they exist (just in case)
DROP TABLE IF EXISTS card_deck_map;
DROP TABLE IF EXISTS card;
DROP TABLE IF EXISTS deck;

-- Create the tables
CREATE TABLE IF NOT EXISTS card (_id INTEGER PRIMARY KEY, cardname UNIQUE);
CREATE TABLE IF NOT EXISTS deck (_id INTEGER PRIMARY KEY, deckname UNIQUE);
CREATE TABLE IF NOT EXISTS card_deck_map (
    card_reference INTEGER REFERENCES card(_id), 
    deck_reference INTEGER REFERENCES deck(_id),
    PRIMARY KEY(card_reference,deck_reference)
);

-- Add 3 cards to the card table
INSERT INTO card (cardname) VALUES ('CARD001'),('CARD002'),('CARD003');
-- Add 3 decks to the deck table
INSERT INTO deck (deckname) VALUES ('DECK001'),('DECK002');
-- Create some mapping entries (aka put some cards into each deck)
INSERT INTO card_deck_map VALUES
    (1,2), -- _id value for CARD001 should be 1, _id value for DECK002 should be 2
    (3,2), -- CARD003 is in DECK002
    (2,1), -- CARD002 is in DECK001
    (1,1) -- CARD001 is also in DECK002
;
-- Have a look at what we have (ignore the id values they mean little to the user)
SELECT deckname, cardname 
FROM deck 
    JOIN card_deck_map ON deck._id = deck_reference
    JOIN card ON card_deck_map.card_reference = card._id
ORDER BY deckname, cardname
;

Вывод из приведенного выше будет: -

enter image description here

Итак, теперь дизайн базы данных подходит, а затем ее можно преобразовать для использования в ROOM.

Сначала 3 объекта Определение данных с использованием объектов Room

Card.java

: -

@Entity (indices = {@Index(value = {"cardname"}, unique = true)})
public class Card {
    @PrimaryKey(autoGenerate = true)
    public long _id;

    @ColumnInfo(name = "cardname")
    public String cardname;

}

Deck.java

: -

@Entity(indices = {@Index(value = "deckname", unique = true)})
public class Deck {

    @PrimaryKey(autoGenerate = true)
    public long _id;

    @ColumnInfo(name = "deckname")
    public String deckname;
}

Card_Deck_Map.java

: -

@Entity(
        primaryKeys = {"card_reference","deck_reference"},
        foreignKeys = {
                @ForeignKey(entity = Card.class,parentColumns = "_id",childColumns = "card_reference"),
                @ForeignKey(entity = Deck.class, parentColumns = "_id",childColumns = "deck_reference")}
                )
public class Card_Deck_Map {

    @ColumnInfo (name="card_reference")
    public long card_reference;

    @ColumnInfo(name="deck_reference")
    public long deck_reference;
}

Теперь вам нужны определения объектов доступа к данным Accessing данные с использованием комнатных DAO

DeckBuildeDao

: -

@ открытый интерфейс Dao DeckBuilderDao {

@Insert(onConflict = OnConflictStrategy.IGNORE)
public long[] insertCards(Card... cards);

@Insert(onConflict = OnConflictStrategy.IGNORE)
public long insertCard(Card card);

@Update
public int updateCardBaseEntries(Card... cards);

@Update
public int updateCardBaseEntry(Card card);

@Delete
public int deleteCardBaseEntried(Card... cards);

@Delete
public int deleteCardBaseEntry(Card card);

@Query("SELECT * FROM card")
public Card[] getAllCards();

@Query("SELECT * FROM card WHERE _id = :id")
public Card getACard(long id);



@Insert(onConflict = OnConflictStrategy.IGNORE)
public long[] insertDecks(Deck... decks);

@Insert(onConflict = OnConflictStrategy.IGNORE)
public long insertDeck(Deck deck);

@Update
public int updateDeckEntries(Deck... decks);

@Update
public int updateDeckEntry(Deck deck);

@Delete
public int deleteDeckEntries(Deck... decks);

@Delete
public int deleteDeckEntry(Deck deck);

@Query("SELECT * FROM deck")
public int getAllDecks();

@Query("SELECT * FROM deck WHERE _id = :id")
public Deck getADeck(long id);


@Insert(onConflict = OnConflictStrategy.IGNORE)
public long[] addCardDeckEntries(Card_Deck_Map... cardDeckMaps);

@Insert(onConflict = OnConflictStrategy.IGNORE)
public long addCardDeckEntry(Card_Deck_Map cardDeckMap);

@Query("SELECT Deck._id,Card.cardname, Deck.deckname " +
        "FROM deck " +
        "JOIN card_deck_map ON deck._id = card_deck_map.deck_reference " +
        "JOIN card ON card_deck_map.card_reference = card._id " +
        "ORDER BY deckname, cardname")
public Cursor getAllDecksWithCards();

}

Класс для базы данных, который связывает сущности и DAO вместе

DeckBuilderDatabase.java

: -

@Database(entities = {Card.class, Deck.class, Card_Deck_Map.class}, version = 1)
public abstract class DeckBuilderDatabase extends RoomDatabase {
    public abstract DeckBuilderDao deckBuilderDao();
}

Теперь действие, которое использует базу данных.

В этом рабочем примере;

  1. база данных будет заполнена двумя колодами (Deck001 и Deck002) с карточной базой, как на колоду игральных карт, кроме джокеров.

    1. Карты будут называться как Ace of Spades, 2 of Hearts.
  2. В колоды будут загружены некоторые карты (отображение)

    1. Deck002 со всеми 52 картами.
    2. Deck001 с3 карты.
  3. Колоды и карты будут извлечены из базы данных и использованы для заполнения ListView.

MainActivity.java

public class MainActivity extends AppCompatActivity {

    public static final String[] SUITS = new String[]{"Spades","Hearts","Clubs","Diamons"};
    public static final int CARDS_IN_A_SUIT = 13;


    DeckBuilderDatabase mDBDB;
    SimpleCursorAdapter mSCA;
    ListView mDecks_and_Cards_List;
    Cursor mCursor;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mDecks_and_Cards_List = this.findViewById(R.id.decksandcards);
        mDBDB = Room.databaseBuilder(this,DeckBuilderDatabase.class,"deckbuilder.db").build();
        populateDB();
    }

    /**
     * Populate the DB with some data, extract the data in the DB and setup the ListView
     */
    private void populateDB() {
        new Thread(new Runnable() {
            @Override
            public void run() {

                Card_Deck_Map currentcdm = new Card_Deck_Map();

                Deck[] decks_to_add = new Deck[]{new Deck(), new Deck()};
                decks_to_add[0].deckname = "DECK001";
                decks_to_add[1].deckname= "DECK002";
                mDBDB.deckBuilderDao().insertDecks(decks_to_add);

                // Build Card base pack of 52 (no Jokers)
                Card[] cardstoadd = new Card[CARDS_IN_A_SUIT * SUITS.length];
                int counter = 0;
                for (int suit = 0; suit < SUITS.length; suit++) {
                    for (int cardval = 0; cardval < CARDS_IN_A_SUIT; cardval++) {
                        Card thiscard = new Card();
                        String thiscardname = generateCardValueDescription(cardval+1,suit);
                        thiscard.cardname = thiscardname;
                        cardstoadd[counter++] = thiscard;
                    }
                }
                mDBDB.deckBuilderDao().insertCards(cardstoadd);

                // Populate the decks with cards Deck002 has full pack of 52 Deck001 has 3 cards
                Card_Deck_Map[] mappings = new Card_Deck_Map[55];
                for (int cardid = 1; cardid < 53; cardid++) {
                    Card_Deck_Map cdm = new Card_Deck_Map();
                    cdm.deck_reference = 2;
                    cdm.card_reference = cardid;
                    mappings[cardid-1] = cdm;
                }
                Card_Deck_Map cdm53 = new Card_Deck_Map();
                cdm53.card_reference = 19;
                cdm53.deck_reference = 1;
                mappings[52] = cdm53;
                Card_Deck_Map cdm54 = new Card_Deck_Map();
                cdm54.card_reference = 10;
                cdm54.deck_reference = 1;
                mappings[53] = cdm54;
                Card_Deck_Map cdm55 = new Card_Deck_Map();
                cdm55.card_reference = 23;
                cdm55.deck_reference = 1;
                mappings[54] = cdm55;
                mDBDB.deckBuilderDao().addCardDeckEntries(mappings);

                // Get the Decks and cards in the decks
                mCursor = mDBDB.deckBuilderDao().getAllDecksWithCards();
                setupOrRefeshListView();
            }
        }).start();
    }


    /**
     * Handles the ListView (also write data to the log for debugging)
     */
    private void setupOrRefeshListView() {
        int rowcount = mCursor.getCount();
        Log.d("ROWS","Number of rows in the Cursor is " + String.valueOf(rowcount));
        while (mCursor.moveToNext()) {
            Log.d(
                    "ROWS",
                    "Row " +
                            String.valueOf(mCursor.getPosition()) +
                            " Has a deck called " +
                            mCursor.getString(mCursor.getColumnIndex("deckname")) +
                            " and a card called " +
                            mCursor.getString(mCursor.getColumnIndex("cardname"))
            );
        }
        if (mSCA == null) {
            mSCA = new SimpleCursorAdapter(
                    this,
                    android.R.layout.simple_list_item_2,
                    mCursor,
                    new String[]{
                            "deckname",
                            "cardname"},
                    new int[]{
                            android.R.id.text1,
                            android.R.id.text2},
                    0
            );
            mDecks_and_Cards_List.setAdapter(mSCA);
        } else {
            mSCA.swapCursor(mCursor);
        }
    }

    /**
     *  Converts numeric cardvalue (1-13) and suit to a decriptive name
     * @param cardvalue
     * @param suit
     * @return
     */
    private String generateCardValueDescription(int cardvalue, int suit) {
        String rv;
        switch (cardvalue) {
            case 1:
                rv = "Ace of " + SUITS[suit];
                break;
            case 11:
                rv = "Jack of " + SUITS[suit];
                break;
            case 12:
                rv = "Queen of " + SUITS[suit];
                break;
            case 13:
                rv = "King of " + SUITS[suit];
                break;
                default:
                    rv = String.valueOf(cardvalue) + " of " + SUITS[suit];
        }
        return rv;
    }
}

Результирующее мини-приложение: -

enter image description here

...