Adding Elements on Many-To-Many Relation

How to add value to a many-to-many field in Django

You create a Meeting and than populate it with Teachers and Students, so:

s1 = Student.objects.create(firstname='Foo', last_name='Bar')
s2 = Student.objects.create(firstname='Qux', last_name='Qux')
t1 = Teacher.objects.create(
firstname='Some',
last_name='One',
email='someone@something.com'
)

m = Meeting.objects.create()
m.student.add(s1, s2)
m.teacher.add(t1)

For more information, see the Many-to-many relationships section of the documentation.

Based on the exception you shared in the question, you created the Meeting model before you made primary keys of type UUIDField. We can fix this problem by:

  1. removing the Meeting model;
  2. run makemigrations;
  3. create a new Meeting model;
  4. run makemigrations again; and
  5. run migrate to update the database.

Android: how to insert data in manyToMany relationship in Room (Java)

First you should amend the Dao's so that they return the id of the inserted row enabling you to ascertain the actual id of the inserted rows. So :-

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

@Insert(onConflict = OnConflictStrategy.REPLACE)
public long insertTag(Tag tag);

@Insert(onConflict = OnConflictStrategy.REPLACE)
public long insertCardWithTags(CardTagCrossRef cardTagCrossRef);

This allows you to retrieve the respective id when you insert either a Card or a Tag (note that for a CardTagCrossRef insertion this will be the rowid, a normally hidden row).

So you could then have use long cardId = cardDAO.insertCard(card.getCard()); and not then need to attempt to use cardTagCrossRef.idCard = card.getCard().getIdCard(); where the card DOES NOT have the id of the inserted card (part of the issue you are facing).

And likewise for the Tag.

So you could use :-

    long cardId = cardDAO.insertCard(card.getCard());
for (Tag t: card.getTagList()) {
long tagId = cardDAO.insertTag(t);
CardTagCrossRef cardTagCrossRef = new CardTagCrossRef();
cardTagCrossRef.idCard = cardId;
cardTagCrossRef.idTag = tagId;
Log.d(TAG, "CardCrossRef:" + cardTagCrossRef.idCard + cardTagCrossRef.idTag);
cardDAO.insertCardWithTags(cardTagCrossRef);
}

However, with a few changes I believe that that can make things far more flexible and have an insert that effectively does what you want within the Dao's.

SO perhaps consider the following that culminates in a working DEMO

Card

@Entity
public class Card {

@PrimaryKey/*(autoGenerate = true) SUGGESTED suppression of autogenerate as will still autogenerate but more efficiently */
private Long idCard;

@ColumnInfo(name = "title")
private String title;

@ColumnInfo(name = "taboo_word_1")
private String tabooWord1;

@ColumnInfo(name = "taboo_word_2")
private String tabooWord2;

@ColumnInfo(name = "taboo_word_3")
private String tabooWord3;

@ColumnInfo(name = "taboo_word_4")
private String tabooWord4;

@ColumnInfo(name = "taboo_word_5")
private String tabooWord5;

/* Constructors added */
public Card(){}

@Ignore
public Card(Long idCard,String title, String tabooWord1, String tabooWord2, String tabooWord3, String tabooWord4, String tabooWord5) {
this.idCard = idCard;
this.title = title;
this.tabooWord1 = tabooWord1;
this.tabooWord2 = tabooWord2;
this.tabooWord3 = tabooWord3;
this.tabooWord4 = tabooWord4;
this.tabooWord5 = tabooWord5;
}

public Long getIdCard() {
return idCard;
}

public void setIdCard(Long idCard) {
this.idCard = idCard;
}

public String getTitle() {
return title;
}

public void setTitle(String title) {
this.title = title;
}

public String getTabooWord1() {
return tabooWord1;
}

public void setTabooWord1(String tabooWord1) {
this.tabooWord1 = tabooWord1;
}

public String getTabooWord2() {
return tabooWord2;
}

public void setTabooWord2(String tabooWord2) {
this.tabooWord2 = tabooWord2;
}

public String getTabooWord3() {
return tabooWord3;
}

public void setTabooWord3(String tabooWord3) {
this.tabooWord3 = tabooWord3;
}

public String getTabooWord4() {
return tabooWord4;
}

public void setTabooWord4(String tabooWord4) {
this.tabooWord4 = tabooWord4;
}

public String getTabooWord5() {
return tabooWord5;
}

public void setTabooWord5(String tabooWord5) {
this.tabooWord5 = tabooWord5;
}
}
  • 2 changes an more flexible constructor and not using autogenerate = true (but that does automatically generate id's BUT without the overheads of the SQLite AUTOINCREMENT which is what autogenerate = true adds).

Tag (similar changes)

@Entity
public class Tag {

@PrimaryKey/*(autoGenerate = true) SUGGESTED suppression of autogenerate*/
private Long idTag;

@ColumnInfo(name = "tag")
private String tag;

public Tag(){}

@Ignore
public Tag(Long idTag, String tag) {
this.idTag = idTag;
this.tag = tag;
}

@Ignore
public Tag(String tag) {
this.tag = tag;
}

public Long getIdTag() {
return idTag;
}

public void setIdTag(Long idTag) {
this.idTag = idTag;
}

public String getTag() {
return tag;
}

public void setTag(String tag) {
this.tag = tag;
}

@Override
public String toString() {
return getTag();
}
}

CardTagCrossRef (added ForeignKey constraints to enforce/manage referential integrity)

@Entity(
primaryKeys = {"idCard", "idTag"}
/* SUGGESTED */
, foreignKeys = {
@ForeignKey(
entity = Card.class,
parentColumns = "idCard",
childColumns = "idCard",
/* SUGGESTED with ForeignKey */
onDelete = CASCADE,
onUpdate = CASCADE
),
@ForeignKey(
entity = Tag.class,
parentColumns = "idTag",
childColumns = "idTag",
/* SUGGESTED with ForeignKey */
onDelete = CASCADE,
onUpdate = CASCADE
)
}
)
public class CardTagCrossRef {

public long idCard;
@ColumnInfo(index = true) /* SUGGESTED */
public long idTag;

public CardTagCrossRef(){}
@Ignore
public CardTagCrossRef(long idCard, long idTag) {
this.idCard = idCard;
this.idTag = idTag;
}
}

CardWithTags

identical other than @Ignore annotation on the CardWithTags(Card card, List<Tag> tagList) constructor to supress warnings about multiple good consctructors.

i.e.

....
@Ignore /*<<<<< SUGGESTED */
public CardWithTags(Card card, List<Tag> tagList) {
this.card = card;
this.tagList = tagList;
}
....

CardDAO (new INSERT + return values)

@Dao
abstract class CardDAO {
/* public interface CardDAO { CHANGED TO abstract class to allow functions with bodies */

@Insert(onConflict = OnConflictStrategy.REPLACE)
abstract long insertCard(Card card); /* Returns long (inserted row id) */

@Insert(onConflict = OnConflictStrategy.REPLACE)
abstract long insertTag(Tag tag); /* Returns long (inserted row id) */

@Insert(onConflict = OnConflictStrategy.REPLACE)
abstract long insertCardWithTags(CardTagCrossRef cardTagCrossRef); /* Returns long (inserted row id) */

/* NEW INSERT */
@Query("")
@Transaction
long[] insert(Card card, List<Tag> tags) {
long[] rv = new long[tags.size() + 1];
int ix = 0;
rv[ix++] = insertCard(card);
if (rv[ix-1] > -1) {
for (Tag t : tags) {
rv[ix++] = insertTag(t);
if (rv[ix-1] > -1) {
insertCardWithTags(new CardTagCrossRef(rv[0],rv[ix-1]));
}
}

}
return rv;
}

// If called on an item not present in the DB it won't do anything
@Update
abstract int updateCard(Card card); /* returns number of updated rows */

@Delete
abstract int deleteCard(Card card); /* returns number of deleted rows */

// With a query method you can also perform complex inserts/updates/deletes
// Transaction needed for relational classes
@Transaction
@Query("SELECT * FROM Card")
/* abstract LiveData<List<CardWithTags>> getAllCards(); COMMENTED OUT to allow demo to run on main thread */
abstract List<CardWithTags> getAllCards(); /* same but not with LiveData */
}

DatabaseTaboom (allow main thread + exportSchema = false to suppress warning)

@Database(entities = {Card.class, Tag.class, CardTagCrossRef.class},
version = 1/* SUGGESTED */ , exportSchema = false)
public abstract class DatabaseTaboom extends RoomDatabase {

public static final String DATABASE_NAME = "db_taboom-1";
abstract CardDAO cardDao();
public static DatabaseTaboom db;

// Singleton pattern
public static DatabaseTaboom getDatabase(Context applicationContext) {
if (db == null) {
db = Room.databaseBuilder(applicationContext, DatabaseTaboom.class, DATABASE_NAME)
.allowMainThreadQueries() /* uncommented for testing */
.build();
}
return db;
}
}

Finally the DEMO MainActivity with some examples of inserting Cards, Tags and CardTagCrossRef's followed by extracting them all outputting the results to the log.

public class MainActivity extends AppCompatActivity {

DatabaseTaboom db;
CardDAO dao;

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

db = DatabaseTaboom.getDatabase(this);
dao = db.cardDao();

/* Simple but long winded */
long c1id = dao.insertCard(new Card(null,"Card1","tw1","tw2","tw3","tw4","tw5"));
long t1id = dao.insertTag(new Tag(null,"TAG1"));
CardTagCrossRef ctcr1 = new CardTagCrossRef();
ctcr1.idCard = c1id;
ctcr1.idTag = t1id ;
dao.insertCardWithTags(ctcr1);
/* Using additional constructor for CardTagCrossRef */
long t2id = dao.insertTag(new Tag("TAG2"));
dao.insertCardWithTags(new CardTagCrossRef(c1id,t2id));
/* More dynamic BUT don't know the actual inserted id's of the Card and Tag */
dao.insertCardWithTags(
new CardTagCrossRef(dao.insertCard(new Card(100l,"Card2","c2tw1","c2tw2","c2tw3","c2tw4","c2tw5")),dao.insertTag(new Tag(null,"TAG3"))));

CardWithTags cwt = new CardWithTags(
new Card(null,"CARD3","c3tw1","c3tw2","c3tw3","c3tw4","c3tw5"),
Arrays.asList(
new Tag(null,"TAG4"), new Tag("TAG5"), new Tag("TAG6")
)
);

/* Amended insert function */
insertCard(cwt,dao);

/* Using new insert funciotn */
dao.insert(
new Card(1000l,"CARD4","c4tw1","c4tw2","c4tw3","c4tw4","c4tw5"),
Arrays.asList(
new Tag(null,"TAG7"), new Tag(500l,"TAG8"),new Tag(null,"TAG9")
)
);
/* Extract the results and output to the log */
for(CardWithTags cwtlist: dao.getAllCards()) {
Log.d("CWTINFO","Card is " + cwtlist.getCard().getTitle() + " TabooWord1 is " + cwtlist.getCard().getTabooWord1() + " it has " + cwtlist.getTagList().size() + " tags. They are:-");
for(Tag t: cwtlist.getTagList()) {
Log.d("CWTINFO_TAG","\tTAG is " + t.getTag());
}
}
}
public void insertCard(CardWithTags card, CardDAO cardDAO) {
final String TAG = "INSERTCARDINFO";

Log.d(TAG, ">>insertCard(): " + card);
/*
executor.execute(() -> {
*/

long currentCardId = cardDAO.insertCard(card.getCard());
for (Tag t: card.getTagList()) {
long currentTagId = cardDAO.insertTag(t);
CardTagCrossRef cardTagCrossRef = new CardTagCrossRef();
cardDAO.insertCardWithTags(new CardTagCrossRef(currentCardId,currentTagId));

/*
cardTagCrossRef.idCard = card.getCard().getIdCard();
cardTagCrossRef.idTag = t.getIdTag();
*/
/*
OR with new Contsructor

CardTagCrossRef ctcr = new CardTagCrossRef(currentCardId,currentTagId);
*/
/* AND THEN cardDAO.insertCardWithTags(cardTagCrossRef); */
Log.d(TAG, "CardCrossRef:" + cardTagCrossRef.idCard + cardTagCrossRef.idTag);
}

/*
// Check if tags already exists
cardListIsUpdatedWithDb = false;
*/
/*})*/;
}
}

When run (after new install as only designed to run the once) the Log includes:-

2022-02-04 13:29:10.569D/INSERTCARDINFO: >>insertCard(): a.a.so70979022javaroom.Card@d751e5e, TAG[TAG4TAG5TAG6]
2022-02-04 13:29:10.573D/INSERTCARDINFO: CardCrossRef:00
2022-02-04 13:29:10.578I/chatty: uid=10194(a.a.so70979022javaroom) identical 1 line
2022-02-04 13:29:10.581D/INSERTCARDINFO: CardCrossRef:00
2022-02-04 13:29:10.600D/CWTINFO: Card is Card1 TabooWord1 is tw1 it has 2 tags. They are:-
2022-02-04 13:29:10.600D/CWTINFO_TAG: TAG is TAG1
2022-02-04 13:29:10.601D/CWTINFO_TAG: TAG is TAG2
2022-02-04 13:29:10.601D/CWTINFO: Card is Card2 TabooWord1 is c2tw1 it has 1 tags. They are:-
2022-02-04 13:29:10.601D/CWTINFO_TAG: TAG is TAG3
2022-02-04 13:29:10.601D/CWTINFO: Card is CARD3 TabooWord1 is c3tw1 it has 3 tags. They are:-
2022-02-04 13:29:10.601D/CWTINFO_TAG: TAG is TAG4
2022-02-04 13:29:10.601D/CWTINFO_TAG: TAG is TAG5
2022-02-04 13:29:10.601D/CWTINFO_TAG: TAG is TAG6
2022-02-04 13:29:10.601D/CWTINFO: Card is CARD4 TabooWord1 is c4tw1 it has 3 tags. They are:-
2022-02-04 13:29:10.601D/CWTINFO_TAG: TAG is TAG7
2022-02-04 13:29:10.601D/CWTINFO_TAG: TAG is TAG8
2022-02-04 13:29:10.601D/CWTINFO_TAG: TAG is TAG9

Via App Inspection then :-

Sample Image

and :-

Sample Image

and :-

Sample Image

Adding Item with Many-to-Many Relationship In Entity Framework

Use the same context instance for the whole processing of your operation and your life will be much easier:

using (var ctx = new MyContext())
{
Article article = ctx.Articles.Single(a => a.Id == articleId);
Tag tag = ctx.Tags.SingleOrDefault(t => t.UrlSlug == tagUrl);
if (tag == null)
{
tag = new Tag() { ... }
ctx.Tags.AddObject(tag);
}

article.Tags.Add(tag);
ctx.SaveChanges();
}

If you don't want to load the article from database (that query is redundant if you know that article exists) you can use:

using (var ctx = new MyContext())
{
Article article = new Article() { Id = articleId };
ctx.Articles.Attach(article);

Tag tag = ctx.Tags.SingleOrDefalut(t => t.UrlSlug == tagUrl);
if (tag == null)
{
tag = new Tag() { ... }
ctx.Tags.AddObject(tag);
}

article.Tags.Add(tag);
ctx.SaveChanges();
}

Hibernate simply adding elements to manytomany from JSON

I found a solution to this, I can just "fetch" the Homework and Material with getById so the DB is not accessed, but I have a reference to them and I can then save it.

Tastypie, add element to a many to many relationship

I implemented this by overriding the save_m2m function of the API Resource. Here is an example using your models.

def save_m2m(self, bundle):
for field_name, field_object in self.fields.items():
if not getattr(field_object, 'is_m2m', False):
continue

if not field_object.attribute:
continue

if field_object.readonly:
continue

# Get the manager.
related_mngr = getattr(bundle.obj, field_object.attribute)
# This is code commented out from the original function
# that would clear out the existing related "Person" objects
#if hasattr(related_mngr, 'clear'):
# Clear it out, just to be safe.
#related_mngr.clear()

related_objs = []

for related_bundle in bundle.data[field_name]:
# See if this person already exists in the database
try:
person = Person.objects.get(name=related_bundle.obj.name)
# If it doesn't exist, then save and use the object TastyPie
# has already prepared for creation
except Person.DoesNotExist:
person = related_bundle.obj
person.save()

related_objs.append(person)

related_mngr.add(*related_objs)

How to Insert data to Many to many relationship tables and retrieving last id In cases where the method accepts two parameters?

How can i retrieve the ID when method looks like this

When you insert multiple rows you get the resultant id's in an Array<Long>

However, for a basic cross reference/mapping table you would rarely, it ever, use the rowid column (which is the value returned).

  • rowid is returned even though the column is implicitly defined. That is with the exception of rarely used WITHOUT ROWID tables, all tables have a hidden column named rowid.

    • When you use INTEGER PRIMARY KEY to define a column, the column is an alias of the rowid column. In room @PrimaryKey for a Long or Int, with or without autoGenerate = true/false (without = false) equates to INTEGER PRIMARY KEY or if autoGenerate = true to INTEGER PRIMARY KEY AUTOINCREMENT.

How do you handle many-to-many relationship Insert?

Here is an example, based upon the available code, with other code created.

So in addition to your DrinkFavouriteAndDrinksCrossRef Entity.

Entities for DrinkFavourite and Item are

@Entity
data class DrinkFavourite(
@PrimaryKey
val drink_id: Int? = null,
val drink_name: String = ""
)
@Entity

data class Drink(
@PrimaryKey var itemId :Long?,
var itemName: String
)

The Dao AllDao is :-

@Dao
interface AllDao {

@Insert
fun insertDrinkFavourite(drinkFavourite: DrinkFavourite) :Long

@Insert
fun insertManyDrinkFavourite(drinkFavourites: List<DrinkFavourite>) :Array<Long>

@Insert
fun insertItem(drink: Drink) :Long

@Insert
fun insertManyItems(drinks: List<Drink>) :Array<Long>

@Insert(onConflict = OnConflictStrategy.IGNORE)
fun insertDrinkFavouriteAndDrinksCrossRef(drinkFavouriteAndDrinksCrossRef: DrinkFavouriteAndDrinksCrossRef) :Long

@Insert(onConflict = OnConflictStrategy.IGNORE)
fun insertManyDrinkFavouriteAndDrinksCrossRef(drinkFavouriteAndDrinksCrossRefs: List<DrinkFavouriteAndDrinksCrossRef>) :Array<Long>
}
  • This caters for inserting a single Entity/row and many Entity/rows for each of the 3 Entities.

The following utilises the 3 many insertions defined in the Dao to insert 3 Drinks, 4 DrinkFavourites and to then insert the 12 DrinkFavouriteAndDrinksCrossRefs (3 Drink * 4 DrinkFavorite) permutations, i.e. all possible permutations, that can be crossed referenced based upon the id's inserted.

class MainActivity : AppCompatActivity() {

lateinit var database: Database

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

database = Room.databaseBuilder(this, Database::class.java, "drinksdb")
.allowMainThreadQueries()
.build()
//val firsItemtid = database.allDao().insertItem( Item(0,"X"))
val manyItemIds = database.allDao().insertManyItems(
listOf(
Drink(null,"A"),
Drink(null,"B"),
Drink(null,"C")
)
)
val manyDrinkFavouriteIds = database.allDao().insertManyDrinkFavourite(
listOf(
DrinkFavourite(null,"DrinkA"),
DrinkFavourite(null,"DrinkB"),
DrinkFavourite(null,"DrinkC"),
DrinkFavourite(null,"DrinkD")
)
)

var xrefcombos = ArrayList<DrinkFavouriteAndDrinksCrossRef>()
for(itemId: Long in manyItemIds) {
for (dfId: Long in manyDrinkFavouriteIds) {
xrefcombos.add( DrinkFavouriteAndDrinksCrossRef(itemId,dfId.toInt()))
}
}
val drinkFavouriteAndDrinksCrossRefIdList = database.allDao().insertManyDrinkFavouriteAndDrinksCrossRef(xrefcombos)
for (dfadcrId in drinkFavouriteAndDrinksCrossRefIdList) {
Log.d("DRKFAVDRNKXREF","Id = " + dfadcrId)
}
}
}

The output is :-

2020-01-17 07:46:40.621 D/DRKFAVDRNKXREF: Id = 1
2020-01-17 07:46:40.621 D/DRKFAVDRNKXREF: Id = 2
2020-01-17 07:46:40.621 D/DRKFAVDRNKXREF: Id = 3
2020-01-17 07:46:40.621 D/DRKFAVDRNKXREF: Id = 4
2020-01-17 07:46:40.621 D/DRKFAVDRNKXREF: Id = 5
2020-01-17 07:46:40.621 D/DRKFAVDRNKXREF: Id = 6
2020-01-17 07:46:40.621 D/DRKFAVDRNKXREF: Id = 7
2020-01-17 07:46:40.621 D/DRKFAVDRNKXREF: Id = 8
2020-01-17 07:46:40.621 D/DRKFAVDRNKXREF: Id = 9
2020-01-17 07:46:40.621 D/DRKFAVDRNKXREF: Id = 10
2020-01-17 07:46:40.621 D/DRKFAVDRNKXREF: Id = 11
2020-01-17 07:46:40.621 D/DRKFAVDRNKXREF: Id = 12

i.e the 12 permutations have been added.

I don't believe that you can effectively use @Insert to do other than insertions according to the Entity/Object being inserted. To do more complex insertions based upon other values, you would use @Query with suitable SQL.

Additional

With regard to :-

data class DrinkFavouritesWithDrinks(
@Embedded
val item: DrinkFavourite,
@Relation(
parentColumn = "item_id",
entityColumn = "drink_id",
associateBy = Junction(DrinkFavouriteAndDrinksCrossRef::class)
)

I believe that this should be :-

data class DrinkFavouriteWithDrinks (

@Embedded
val drinkFavourite: DrinkFavourite,
@Relation(
entity = Drink::class,
entityColumn = "itemId",
parentColumn = "drink_id",
associateBy = Junction(
DrinkFavouriteAndDrinksCrossRef::class,entityColumn = "item_id",parentColumn = "drink_id"))
val drinks: List<Drink> = emptyList()
)
  • You get all the Drinks per DrinkFavourite, so singular rather than plural is a better name.
  • the association needs to know the columns to associate by.

You could than have a Dao method such as :-

@Query("SELECT * FROM drinkfavourite")
fun getAllDrinkFavouritesWithDrinks() :List<DrinkFavouriteWithDrinks>

Adding to the following to the MainActivity above :-

    val drinkFavouriteWithDrinksList = database.allDao().getAllDrinkFavouritesWithDrinks()
var sb = StringBuilder()
for (dfwd: DrinkFavouriteWithDrinks in drinkFavouriteWithDrinksList) {
sb.clear().append("DrinkFavourite = ").append(dfwd.drinkFavourite)
for (d: Drink in dfwd.drinks) {
sb.append("\n\tDrink = ").append(d.itemName)
}
Log.d("DRINKFAVINFO", sb.toString())
}

Results in :-

2020-01-17 11:39:52.762 D/DRINKFAVINFO: DrinkFavourite = DrinkFavourite(drink_id=1, drinkFavouriteName=DrinkA)
Drink = A
Drink = B
Drink = C
2020-01-17 11:39:52.763 D/DRINKFAVINFO: DrinkFavourite = DrinkFavourite(drink_id=2, drinkFavouriteName=DrinkB)
Drink = A
Drink = B
Drink = C
2020-01-17 11:39:52.763 D/DRINKFAVINFO: DrinkFavourite = DrinkFavourite(drink_id=3, drinkFavouriteName=DrinkC)
Drink = A
Drink = B
Drink = C
2020-01-17 11:39:52.763 D/DRINKFAVINFO: DrinkFavourite = DrinkFavourite(drink_id=4, drinkFavouriteName=DrinkD)
Drink = A
Drink = B
Drink = C
  • Not the best example as every DrinkFavourite has all three drinks

Insert in Many-To-Many-Relations in Kotlin Rooms

This isn't going to a simple one line fix.

First you need to be able to detect if a Zutaten exists and probably if a Rezepte exists (so a RezeptWithZutat for an existing Rezept does create a new one but adds to the existing one).

So first two new Dao's

  • Note instead of an interface, the following code uses an abstract class so abstract fun is used instead of fun.
  • Also all dao's have been combined into one abstract class namely AllDao.
  • Note I don't do LiveData stuff so the code does not use LiveData and the code I've copied has had all LiveData removed to allow a working demonstration.

:-

@Query("SELECT zutatid FROM zutaten_table WHERE zutname=:zutname")
abstract fun getZutatenIdByName(zutname: String): Int
@Query("SELECT rezeptid FROM rezepte_table WHERE rezname=:rezname")
abstract fun getRezepteIDByName(rezname: String): Int

These will return the id or 0 if the zutaten/rezept doesn't exist.

Next comes a function, in AllDao (it uses the Dao's directly), to insert the RezeptWithZutat:-

fun insertZutatenWithRezept(rezeptWithZutat: RezeptWithZutat)  {
var rid = getRezepteIDByName(rezeptWithZutat.rezept.rezname)
/* find or insert Rezepte according to name */
if (rid < 1) {
rid = insert(RezepteData(0,rezeptWithZutat.rezept.rezname,rezeptWithZutat.rezept.bild)).toInt()
}
if (rid < 1) {
/*
could not find existing Rezepte or insert a new one?????
should not happen but in case do something here
*/
} else {
for (z in rezeptWithZutat.zutaten) {
var zid = getZutatenIdByName(z.zutname)
if (zid < 1) {
zid = insert(ZutatenData(0, z.zutname)).toInt()

}
if (zid < 1) {
/*
could not find existing Zutaten or insert new one?????
should not happen but in case do something here
*/
} else {
insert(RefZutatRezept(zutatid = zid, rezeptid = rid))
}
}
}
}
  • not the most efficient way as the non-existent Zutatens could be inserted together (but with more complicated code) and likewise the RefZutatRezept could be insert all together (again with more complicated code).

Demonstration (run on main thread for convenience/brevity)

using the above and your code/dao's (as changed above) then in an Activity :-

    db = TheDatabase.getInstance(this)
dao = db.getAllDao()

val r1 = dao.insert(RezepteData(rezeptid = 0,rezname = "REZ1",bild = 1))
val r2 = dao.insert(RezepteData(rezeptid = 0, rezname = "REZ2", bild = 1))

val milk = dao.insert(ZutatenData(zutatid = 0,zutname = "Milk"))
val sugar = dao.insert(ZutatenData(zutatid = 0,zutname = "Sugar"))
val flour = dao.insert(ZutatenData(zutatid = 0,zutname = "Flour"))
val eggs = dao.insert(ZutatenData(zutatid = 0,zutname = "Eggs"))

dao.insert(RefZutatRezept(milk.toInt(),r1.toInt()))
dao.insert(RefZutatRezept(flour.toInt(),r1.toInt()))
dao.insert(RefZutatRezept(eggs.toInt(),r1.toInt()))

Log.d("STAGE1", "data before adding R-With-Z")
showAllRezeptWithZutatsInDatabase()
var newRWithZ = RezeptWithZutat(
RezepteData(0,"REZ3",1),zutaten = listOf(
ZutatenData(0,"salt"),
ZutatenData(0,"nutmeg"),
ZutatenData(0,"cornflour"),
ZutatenData(0,"corriander"),
ZutatenData(0,"Milk")


Related Topics



Leave a reply



Submit