I am using play2.2.1 and trying to create a ManyToMany relation between Jobads and JobCategory models.
My Jobads.java
package models;
@Entity
public class Jobads extends Model {
@Id
public Long id;
@ManyToOne
public Employers employer;
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name = "jobads_jobcategories")
public List<Jobcategories> jobcategory;
@ManyToOne
public Joblocations joblocations;
@Required
public String jobtype;
@Required
public String title;
@Required
public String text;
@Required
public Long salary;
@Required
public String experience;
@Required
public String active;
@Formats.DateTime(pattern="yyyy-MM-dd hh:mm:yy")
public Date created_time = new Date();
@Formats.DateTime(pattern="yyyy-MM-dd hh:mm:yy")
public Date modified_time ;
@Required
@Formats.DateTime(pattern="yyyy-MM-dd")
public Date expire_date ;
public static Finder<Long,Jobads> find = new Finder<Long,Jobads>(
Long.class, Jobads.class
);
public static Jobads create(Jobads ja) {
ja.save();
ja.saveManyToManyAssociations("jobcategory");
return ja;
}
}
My view:
<form action="@routes.JobAdController.save()" method="post" onsubmit="return checkEmpty();">
<div class="row">
<div class="col-md-6">
<div class="block">
<div class="header">
<h2>Create A New Job</h2>
</div>
<div class="content controls">
<div class="form-row">
<div class="col-md-3">Employer</div>
<div class="col-md-9">
<select class="form-control" name="employer.id" id="employer_id">
<option value="select">Select Employer</option>
@for(emp<-employersList) {
<option value="@emp.id">@emp.company_name</option>
}
</select>
</div>
</div>
<div class="form-row">
<div class="col-md-3">Category</div>
<div class="col-md-9">
<select class="form-control" name="jobcategory.id" id="jobcategory_id">
<option value="select">Select Job Category</option>
@for(jc<-jobcategoryList) {
<option value="@jc.id">@jc.name</option>
}
</select>
</div>
</div>
<div class="form-row">
<div class="col-md-3">Location</div>
<div class="col-md-9">
<select class="form-control" name="joblocations.id" id="joblocation_id">
<option value="select">Select Job Location</option>
@for(jl<-joblocationList) {
<option value="@jl.id">@jl.country,@jl.state,@jl.city</option>
}
</select>
</div>
</div>
<div class="form-row">
<div class="col-md-3">Job Type</div>
<div class="col-md-9">
<select class="form-control" name="jobtype" id="jobtype">
<option value="select">Select Job Type</option>
<option value="parttime">Part Time</option>
<option value="fulltime">Full Time</option>
</select>
</div>
</div>
<div class="form-row">
<div class="col-md-3">Title</div>
<div class="col-md-9"><input type="text" class="form-control" placeholder="Title" name="title" required="required"/></div>
</div>
<div class="form-row">
<div class="col-md-3">Text</div>
<div class="col-md-9"><textarea class="form-control" name="text" required="required"></textarea></div>
</div>
<div class="form-row">
<div class="col-md-3">salary</div>
<div class="col-md-9"><input type="text" class="form-control" placeholder="Salary per month" name="salary" required="required"/></div>
</div>
<div class="form-row">
<div class="col-md-3">expire date</div>
<div class="col-md-9"><input type="date" class="form-control" placeholder="expiry date" name="expire_date" id="expire_date" required="required" /></div>
<input type="hidden" class="form-control" placeholder="expiry date" name="exp_date" id="exp_date" />
</div>
<div class="form-row">
<div class="col-md-3">Active</div>
<div class="col-md-9">
<select class="form-control" name="active" id="active">
<option value="active">Active</option>
<option value="inactive">Inactive</option>
</select>
</div>
</div>
<div class="form-row">
<div class="col-md-12">
<button type="submit" class="btn btn-default btn-block">Add</button>
</div>
</div>
</div>
</div>
</div>
</div>
</form>
And my controller:
public class JobAdController extends Controller {
public static Result save() {
Form<Jobads> jobadsFormData = jobadsForm.bindFromRequest();
if (jobadsFormData.hasErrors()) {
System.out.println("Error in form");
return badRequest();
} else {
Jobads.create(jobadsFormData.get());
return redirect(controllers.routes.JobAdController.index());
}
}
}
I don't have a variable for Jobads in Jobcategory model because I dont need it there. So a default table is created named jobads_jobcategories. My problem is that when I am trying to insert a data in jobads table it is inserted perfectly but the mapping ids are not saved in jobads_jobcategories table.
My jobcategorylist was empty thanks to rtruszk for helping me out. Play is not able to bind the mutiple valued variable from request to models manytomany list variable (I am still tryng to figure this out why play is doing that)
So what I did to solve this problem, I changed the form method to get the value of mutiple valued variable from url in my controller then created a new list and added to my Form variable. It's optional but I added getter and setter and changed my list name. Code given below
For GET request
public static Result save() {
List<Long> jobCatList = new ArrayList<Long>();
final Set<Map.Entry<String, String[]>> entries = request().queryString().entrySet();
for (Map.Entry<String, String[]> entry : entries) {
final String key = entry.getKey();
final String value = Arrays.toString(entry.getValue());
System.out.println(key + " " + value);
if (key.equalsIgnoreCase("jobcategories.id")) {
String val = value;
val = val.replace("[", "");
val = val.replace("]", "");
String[] a = val.split(",");
for (int i = 0; i < a.length; i++) {
jobCatList.add(Long.parseLong(a[i].trim()));
}
}
}
List<Jobcategories> jobCatObList = new ArrayList<Jobcategories>();
for (Long id : jobCatList) {
System.out.println("Id are:" + id);
jobCatObList.add(Jobcategories.findById(id));
}
System.out.println(request().getQueryString("jobcategories.id"));
Form<Jobads> jobadsFormData = jobadsForm.bindFromRequest();
System.out.println("\nCategory Form are:" + (jobadsFormData.get()).getJobcategories());
(jobadsFormData.get()).setJobcategories(jobCatObList);
if (jobadsFormData.hasErrors()) {
return badRequest();
} else {
Jobads.create(jobadsFormData.get());
return redirect(controllers.routes.JobAdController.index());
}
}
OR
For POST request
public static Result save() {
Form<Jobads> jobadsFormData = jobadForm.bindFromRequest();
Map<String, String[]> formUrlEncoded = request().body().asFormUrlEncoded();
List<Jobcategories> fa = new ArrayList<Jobcategories>();
for (String key : formUrlEncoded.keySet()) {
String[] values = formUrlEncoded.get(key);
for (String val : values) {
if ("jobcategories.id".equals(key)) fa.add(Jobcategories.findById(Long.valueOf(val)));
}
}
if (jobadsFormData.hasErrors()) {
return badRequest();
} else {
(jobadsFormData.get()).setJobcategories(fa);
Jobads.create(jobadsFormData.get());
return redirect();
}
}
I know that this method is not the correct way of saving manytomany relation but I didn't have any other option to resolve my problem.
If anybody have a better solution then do post it because I am trying this for days and have achieves this much.
And why play is not able to map or save the manytomany relation?
Your mapping is good. Try running following test to be sure of that:
@Test
public void ebeanTest() {
FakeApplication app = Helpers.fakeApplication(Helpers.inMemoryDatabase());
Helpers.start(app);
Jobcategories jc = new Jobcategories();
jc.id=1l;
jc.title="cat 1";
Jobads job = new Jobads();
job.id=2l;
job.title = "job 1";
job.jobcategory.add(jc);
Jobads.create(job);
Jobads foundJob = Jobads.find.byId(2l);
for(Jobcategories jobc:foundJob.jobcategory) {
System.out.println("id: "+jobc.id);
System.out.println("title: "+jobc.title);
}
}
You should have following result:
[play-java] $ test
id: 1
title: cat 1
You can also remove following line from your Jobads class because it is obsolete there:
ja.saveManyToManyAssociations("jobcategory");
It seems that you have error in your form. I think that
jobadsFormData.get()
returns Jobads with empty list of jobcategories. And then such object is saved correctly.
EDIT I see in your view code that you use 'select' HTML element for selecting Jobcategories. Why do you do that? You have list of Jobcategories in your Jobads class but in 'select' element you can select only one category. So this HTML element is good for selecting employer or joblocation but not for selecting list. So here is the problem. 'select' element maps good to fielld but not to list.
EDIT2 So you have to change two things:
- Add multiple="multiple" to your HTML select element
- Check which categories are selected while saving form. See this post for details
Try to add JoinColumn(s) for jobads and/or jobcategories
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name = "jobads_jobcategories", joinColumns = {@JoinColumn(name="Jobads_ID", referencedColumnName="ID")})
public List<Jobcategories> jobcategory;
I want to ask if you try it in a comment, but I don't have enough reputation.
来源:https://stackoverflow.com/questions/26945159/manytomany-relation-not-able-to-save-mapped-id-in-mapping-table-in-play-framewor