my problem is my database mapping and i don't get it working.
I've done this Tutorial.
class Comment {
String comment
Date dateCreated // Predefined names by Grails will be filled automatically
Date lastUpdated // Predefined names by Grails will be filled automatically
User user
// delete a comment for a feedback if the feedback item is deleted
static belongsTo=[feedback:Feedback]
static mapping = {
feedback column: 'COMMENT_FEEDBACK_ID', joinTable: false
}
static constraints = {
comment (blank:false, nullable: false, size:5..500)
user (nullable: true) // Comments are allowed without a user
}
String toString(){
if (comment?.size()>20){
return comment.substring(0,19);
} else
return comment;
}}
class Feedback {
String title
String feedback
Date dateCreated // Predefined names by Grails will be filled automatically
Date lastUpdated // Predefined names by Grails will be filled automatically
// relationship to the other classes
User user
static hasMany=[comments:Comment]
static mapping = {
comments column: 'FEEDBACK_COMMENT_ID', joinTable: false
}
// constrains are defined as static
static constraints ={
title(blank:false, nullable: false, size:3..80)
feedback(blank:false, nullable:false, size:3..500)
user(nullable:false)
}}
class User {
String name
String email
String webpage
static constraints = {
name (blank:false, nullable:false, size:3..30, matches:"[a-zA-Z1-9_]+")
email (email:true)
webpage (url:true)
}
String toString(){
return name;
}
}
When I try to delete a User which is connected to a feedback/ a comment, I get an error:
Cannot delete or update a parent row: a foreign key constraint fails
(guestbook.comment, CONSTRAINT FK_mxoojfj9tmy8088avf57mpm02
FOREIGN KEY (user_id) REFERENCES user (id))
What should the mapping look like?
You have multiple problems with the domain design, first remove the user from comment ,as the user already have a comment from feedback. if you still wish to keep that design, then define belongsTo to User,in both Comment and Feedback.
Try this...
Add hasOne Feedback to User
class User {
String name
String email
String webpage
hasOne = [feedback:Feedback ]
static constraints = {
name (blank:false, nullable:false, size:3..30, matches:"[a-zA-Z1-9_]+")
email (email:true)
webpage (url:true)
}
String toString(){
return name;
}
}
Add Feedback belongsTo User and cascade on delete for Comment
class Feedback {
String title
String feedback
Date dateCreated // Predefined names by Grails will be filled automatically
Date lastUpdated // Predefined names by Grails will be filled automatically
// relationship to the other classes
User user
static belongsTo = [User]
static hasMany=[comments:Comment]
static mapping = {
comments cascade: 'all-delete-orphan',column: 'FEEDBACK_COMMENT_ID', joinTable: false
}
// constrains are defined as static
static constraints ={
title(blank:false, nullable: false, size:3..80)
feedback(blank:false, nullable:false, size:3..500)
user(nullable:false)
}}
Simply remove User from Comment
class Comment {
String comment
Date dateCreated // Predefined names by Grails will be filled automatically
Date lastUpdated // Predefined names by Grails will be filled automatically
//User user
// delete a comment for a feedback if the feedback item is deleted
/static belongsTo=[User,feedback:Feedback]
static belongsTo=[feedback:Feedback]
static mapping = {
feedback column: 'COMMENT_FEEDBACK_ID', joinTable: false
}
static constraints = {
comment (blank:false, nullable: false, size:5..500)
//user (nullable: true) // Comments are allowed without a user
}
String toString(){
if (comment?.size()>20){
return comment.substring(0,19);
} else
return comment;
}}
Related
I am working with jhipster. I need to create a new table for auditing my database changes and link it with the default jhi_persistenet_audit_event table generated by the Jhipster. How I can get the current logged user record from the jhi_persistenet_audit_event table to link that id to my new table?
Solution 1: Principal principal
#RequestMapping(value = {"/", ""})
public String start(Principal principal, Model model) {
String currentUser = principal.getName();
return currentUser;
}
Solution 2: Authentication authentication
#RequestMapping(value = {"/", ""})
public String currentUserName(Authentication authentication) {
return authentication.getName();
}
Solution 3: SecurityContextHolder
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (principal instanceof UserDetails) {
String username = ((UserDetails)principal).getUsername();
} else {
String username = principal.toString();
}
Details 1 Details 2
I am using jaxrs:0.10 and I have default generated resources for a domain OrderDetails. And the client will POST json which will contain domain OrderDetails object as well as other two parameters userName and password, so that only authenticated users consume the resource. I can simply save to database for domain OrderDetails only without authentation(i.e.the JSON is same as the domain.) by posting a JSON but by adding the other two parameters for authentication is a bit different thing. How to accomplish this task, my need is :
1)The client posts the json with userName,password and OrderDetails object.
2)I need to authenticate the user credentials for OrderDetails object to save to the database.
For time being user credentials will the static.
My code for domain OrderDetails is :
class OrderDetails {
Date orderDate
Long orderNumber
Float subTotal
Float shipping
Float discount
Float netTotalPaid
boolean creditApplied
Long transactionId
String specialInstruction
DeliveryStatus deliveryStatus
Long memberId
String localOffice
static constraints = {
orderDate nullable: true
orderNumber nullable: true
subTotal nullable: true
shipping nullable: true
discount nullable: true
netTotalPaid nullable: true
creditApplied nullable: true
transactionId nullable: true
specialInstruction nullable: true
deliveryStatus nullable: true
memberId nullable: true
localOffice nullable: true
}
}
And the generated Resources are :
#Path('/api/v1/orderDetails')
#Consumes(['application/json'])
#Produces(['application/json'])
class OrderDetailsCollectionResource {
def orderDetailsResourceService
#POST
Response create(OrderDetails dto) {
created orderDetailsResourceService.create(dto)
}
#GET
Response readAll() {
ok orderDetailsResourceService.readAll()
}
#Path('/{id}')
OrderDetailsResource getResource(#PathParam('id') Long id) {
new OrderDetailsResource(orderDetailsResourceService: orderDetailsResourceService, id:id)
}
}
And :
#Consumes(['application/json'])
#Produces(['application/json'])
class OrderDetailsResource {
def orderDetailsResourceService
def id
#GET
Response read() {
ok orderDetailsResourceService.read(id)
}
#PUT
Response update(OrderDetails dto) {
dto.id = id
ok orderDetailsResourceService.update(dto)
}
#DELETE
void delete() {
orderDetailsResourceService.delete(id)
}
}
Your wrapper:
class AuthOrder {
OrderDetails orderDetails;
Token userToken;
Password password;
}
Now you expect an AuthOrder-Json-Object instead of an OrderDetails. In your GET/PUT/DELETE-Operations you read the user and password and check if it is allowed to do the job. Then pass on the OrderDetails-Object.
For the json-rest-authentication in general I suggest you to read how-do-people-handle-authentication-for-restful-apis-technology-agnostic
EDIT: Example for #PUT;
#Consumes(['application/json'])
#Produces(['application/json'])
class OrderDetailsResource {
def orderDetailsResourceService
def id
#GET
Response read() {
ok orderDetailsResourceService.read(id)
}
#PUT
Response update(AuthOrder dto) {
if (validateUser(dto.getUserName, dto.getUserPassword)) {
OrderDetails orderDetails= dto.getOrderDetails();
dto.id = id
ok orderDetailsResourceService.update(dto)
} else
//not ok response
}
}
#DELETE
void delete() {
orderDetailsResourceService.delete(id)
}
}
I have a grails domain hasMany and belongsTo relationship as the below :
I am wanting to sort based on 'Submission' 'lastUpdated' 'desc'
class User {
String username
String password
static hasMany = [ submissions: Submission ]
static mapping = {
sort submissions: 'desc' // This doesn't do anything?
}
}
class Submission {
String reference
Date dateCreated
Date lastUpdated
static belongsTo = User
}
So everytime I collect a User's submissions, I would like it default sorted as lastUpdated desc. The equivalent mysql statement would be the following
select (fields) from submission order by last_updated desc;
Am i missing something?
Thanks greatly!
Because this is a unidirectional relationship, the following solution works perfectly!
class User {
String username
String password
SortedSet submissions
static hasMany = [ submissions: Submission ]
}
class Submission implements Comparable {
String reference
Date dateCreated
Date lastUpdated
static belongsTo = User
#Override
public int compareTo(obj) {
obj.lastUpdated.compareTo(lastUpdated)
}
}
I think you should read how to set default sort order in assosiation
From GORM documentation
Finally, you can configure sorting at the association level:
class Airport {
...
static hasMany = [flights: Flight]
static mapping = {
flights sort: 'number', order: 'desc'
}
}
I seemed to have stumbled upon a bug in grails gorm/hibernate with mysql.
I have an abstractDomainClass which is under sources/groovy. In this abstract domain class I have defined a manytomany relationship.
Then I have defined a DomainClass which inherites from the abstract domain class. Now when I use this with MicrosftSQL Server it all works fine, but when I try to use this with MySQL I get the folowing error message:
Caused by MappingException: Foreign key (FK96018AD68612E650:domain_class [])) must have same number of columns as the referenced primary key (user_group [id])
My abstractDomainClass lookse like this:
abstract class AbstractDomainClass {
String name
Set<UserGroup> userGroups
static hasMany = [userGroups: UserGroup]
static constraints = {
name(nullable: false, blank: false)
}
String toString() {
return name
}
}
My DomainClass looks like this:
class DomainClass extends AbstractDomainClass {
String earliestEntryDate
static constraints = {
earliestEntryDate(nullable: true, blank: false, attributes: [sortable: false])
}
}
The UserGroup Domain class looks like this
class UserGroup {
String name
static hasMany = [domainClasses: DomainClass]
static belongsTo = [DomainClass]
static constraints = {
name(nullable: false, blank: false)
}
#Override
String toString() {
name
}
}
I am using Code First Entity Framework 4.1. The two entities that I am using are "State" and "User". Each State entry has a "CreatedBy" User and "ModifiedBy" User properties as given below.
public class State {
public virtual User CreatedBy { get; set; }
public virtual User ModifiedBy { get; set; }
}
The User entity doesn't have any back reference to State entity, that is State => User is "Unidirectional".
The problem occurs when there is a detached State entity which has same "CreatedBy" and "ModifiedBy" User properties. When I try to attach State Entity to the dbContext, the EntityFramework complains that duplicate entry found by ObjectStateManager. I was looking for a simple solution for this issue.
One solution would be to check if a User with the same key is already in the context and if yes, replace the detached User references in your State entity by the objects which are attached to the context. Say, state is the new State entity to attach:
if (state.CreatedBy != null)
{
var attachedCreatedBy = context.ChangeTracker.Entries()
.Where(e => e.Entity is User
&& e.Cast<User>().Entity.Id == state.CreatedBy.Id)
.Select(e => e.Entity)
.SingleOrDefault();
if (attachedCreatedBy != null)
state.CreatedBy = attachedCreatedBy;
}
if (state.ModifiedBy != null)
{
var attachedModifiedBy = context.ChangeTracker.Entries()
.Where(e => e.Entity is User
&& e.Cast<User>().Entity.Id == state.ModifiedBy.Id)
.Select(e => e.Entity)
.SingleOrDefault();
if (attachedModifiedBy != null)
state.ModifiedBy = attachedModifiedBy;
}
context.States.Attach(state); // now it should not throw an exception anymore
Well, I would not call this a "simple solution" though. But I don't know another one. If you had foreign key properties CreatedById and ModifiedById in State it would become easier. You could just set the navigation properties CreatedBy and ModifiedBy to null and only set the foreign key properties to the Ids of the related users.