I have Subscriber and Contact domain and a subscriber can have many contacts(one to many) in grails app. When I try to delete data from table contact it throws error like DBCExceptionReporter Cannot delete or update a parent row: a foreign key constraint fails (
vprocure5 .
subscriber_contact , CONSTRAINT
FKC5D3AF49E9F29F5 FOREIGN KEY (
contact_id ) REFERENCES
contact (
id ))
.
According to error message, I can not delete a parent row, but actually I am trying to delete contact data which are children of "Subscriber" domain. Here Subscriber should be parent and Contact should be child domain if I am not wrong.
Subscriber domain
static hasMany= [contacts: Contact ]
Contact domain
static belongsTo = [Subscriber ]
ContactController.grooby
package com.vproc.member
import org.springframework.dao.DataIntegrityViolationException
class ContactController {
def springSecurityService
def subscriberService
def imageUploadService
def searchableService
def autoCompleteService
static allowedMethods = [save: "POST", update: "POST", delete: "POST"]
def index() {
redirect(action: "list", params: params)
}
def list() {
Subscriber loggedinSubscriber = Subscriber.get( springSecurityService.principal.id )
List<Contact>contactsList = new ArrayList<Contact>();
loggedinSubscriber?.contacts.each { it ->
contactsList.add(it)
}
[contactInstanceList:contactsList , contactInstanceTotal: contactsList.size() ]
}
def create() {
[contactInstance: new Contact(params)]
}
def save() {
if (params.birthday){
params.birthday = (new SimpleDateFormat("MM/dd/yyyy")).parse(params.birthday)
}
def contactInstance = new Contact(params)
Subscriber loggedinSubscriber = Subscriber.get( springSecurityService.principal.id )
if (loggedinSubscriber == null)
System.out.println("not able to save")
else {
if (!loggedinSubscriber.contacts){
loggedinSubscriber.contacts = new ArrayList<Contact>();
}
loggedinSubscriber.contacts.add(contactInstance)
if (!loggedinSubscriber.save(flush: true)) {
flash.message = message(code: 'default.created.message', args: [message(code: 'contact.label', default: 'Contact'), contactInstance.id])
render(view: "create", model: [contactInstance: contactInstance])
return
}
}
flash.message = message(code: 'default.created.message', args: [message(code: 'contact.label', default: 'Contact'), contactInstance.id])
redirect(action: "list")
}
def ajaxDelete = {
def contactInstance = Contact.get( params.id );
contactInstance.tags.clear();
println "=========================="
if(contactInstance) {
try {
println "+++++++++++++++++++++++++"
contactInstance.delete(flush:true)
render "contact ${params.id} deleted"
}
catch(org.springframework.dao.DataIntegrityViolationException e) {
render "contact ${params.id} could not be deleted"
}
}
else {
flash.message = "contact not found with id ${params.id}"
render(action:list)
}
}
Contact.groovy
package com.vproc.member
import java.util.Date;
import com.vproc.common.Tag;
import com.vproc.enquiry.ContactType;
import grails.converters.JSON;
class Contact {
String name
String phoneNumber
String emailAddress
Gender gender
String url
String note
byte[] image
String address
Date dateCreated
Date lastUpdated
ContactType contactType
Date birthday
static belongsTo = [Subscriber ]
static hasMany = [tags:Tag , shares: SharedContact]
static constraints = {
image nullable: true
phoneNumber nullable: true
url nullable :true
address nullable :true
gender nullable :true
note nullable :true
contactType nullable :true
birthday nullable :true
}
static mapping = {
tags cascade: "all-delete-orphan"
}
//static searchable = [only: ['name', 'emailAddress']]
static searchable = true
static scaffold = true
//static searchable = true
}
Subscriber.groovy
package com.vproc.member
import java.util.Date;
class Subscriber extends PartyRole{
transient springSecurityService
String username
String password
boolean enabled
boolean accountExpired
boolean accountLocked
boolean passwordExpired
StatusEnum status
Date dateCreated
Date lastUpdated
List<Contact> contacts ;
static belongsTo = [ customer: Customer]
static hasMany = [scontacts: Contact]
static mapping = {
password column: '`password`'
}
Set<Role> getAuthorities() {
SubscriberRole.findAllBySubscriber(this).collect { it.role } as Set
}
def beforeInsert() {
encodePassword()
}
def beforeUpdate() {
if (isDirty('password')) {
encodePassword()
}
}
protected void encodePassword() {
password = springSecurityService.encodePassword(password)
}
}
Any idea how I can delete contact records here?
delete action in Contact controller
def ajaxDelete = {
Subscriber loggedinSubscriber = Subscriber.get( springSecurityService.principal.id )
def contactInstance = Contact.get( params.id );
contactInstance.tags.clear();
loggedinSubscriber.removeFromContacts(contactInstance)
println "=========================="
if(contactInstance) {
try {
println "+++++++++++++++++++++++++"
contactInstance.delete(flush:true)
render "contact ${params.id} deleted"
}
catch(org.springframework.dao.DataIntegrityViolationException e) {
render "contact ${params.id} could not be deleted"
}
}
else {
flash.message = "contact not found with id ${params.id}"
render(action:list)
}
}
Because you've mapped the relationship like this:
static belongsTo = [Subscriber]
Grails has created a join table called subscriber_contact. You can see this in your error message:
delete or update a parent row: a foreign key constraint fails (vprocure5. subscriber_contact , CONSTRAINTFKC5D3AF49E9F29F5FOREIGN KEY (contact_id) REFERENCEScontact(id))
In this case, you would actually need to use the removeFrom method on Subscriber to delete the contact.
subscriberInstance.removeFromContacts(contactInstance)
Then, GORM will internally handle removing the row from the subscriber_contact table.
Optionally, you should be able to map your relationship using the map notation:
static belongsTo = [subscriber: Subscriber]
This should negate the need for Grails to create the join table and you should be able to delete the contact directly since it will just contain a FK to the subscriber table.
I created a grails app with Subscriber and Contact modeled the way you have them. I then wrote the following test, which passes:
@TestFor(Contact)
@Mock([Contact, Subscriber])
class ContactTests {
void setUp() {
def subscriber = new Subscriber(name: 's1')
def contact = new Contact(name: 'c1')
subscriber.addToContacts(contact)
subscriber.save()
}
void testDeleteContactFromSubscriber() {
assertEquals(Contact.list().size(), 1)
def dbSubscriber = Subscriber.findByName('s1')
def dbContact = Contact.findByName('c1')
dbSubscriber.removeFromContacts(dbContact)
dbContact.delete()
assertEquals(Contact.list().size(), 0)
}
}
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.