Play! Framework 2.X, form handling - forms

I am new to using Play! Framework 2.X and have a simple question.
How can i send to my method Job.create(filledJob) a fully set Job object? Meaning that Company object including in Job object is filled too.
I have the following:
public class Job {
public String title;
public Company company;
}
public class Company {
public String name;
public String email;
}
I have a form in my template, containing a Job information section and a Company section
#(jobForm: Form[Job], companyForm: Form[Company])
#form(routes.Application.newJob()) {
#inputText(jobForm("title"))
#inputText(companyForm("name"))
<input type="submit" value="Create">
}
My controller(Application.java) looks like that:
public class Application extends Controller {
static Form<Job> jobForm = form(Job.class);
static Form<Company> companyForm = form(Company.class);
public static Result index() {
return ok(
views.html.index.render(jobForm, companyForm)
);
}
public static Result newJob() {
Form<Job> filledForm = jobForm.bindFromRequest();
Job.create(filledForm.get());
return redirect(routes.Application.index());
}
}
Ideally, i would like to send to my method Job.create(job), with job with all the fields set (string job title as well as Company object). It must be a numpty question, i appologize for that. Any help would be greatly appreciated
Many thanks

You can't use #inputText(companyForm("name")) if you want bind the form directly into object, but instead you can use a select form helper for selecting the company, check ie. computer-database sample it's quite similar case...
On the other hand if you have a lot of companies and don't want to create huge select consider another scenario: just instead route like /job/new use /company/:companyId/add-job in other words just you'll send a form and bind it from request + additionaly will get Company by id in route param and will add to object, pseudo code:
public static Result addJobToCompany(Integer companyId){
Job job = form(Job.class).bindFromRequest().get();
job.company = Company.find.byId(companyId);
job.save();
return redirect(routes.Application.jobDetails(job.id));
}

Ok i am replying to my own question as i must not have explained my question clearly.
To make it simple : I needed to set the Company object from a form. Find below my solution
Hope it will help you.
public class Job {
public String title;
#Valid
public Company company;
}
public class Company {
public String name;
public String email;
}
#(jobForm: Form[Job], companyForm: Form[Company])
#form(routes.Application.newJob()) {
#inputText(jobForm("title"))
#inputText(jobForm("company.name"))
<input type="submit" value="Create">
}

Related

Spring boot REST application

I am trying to make a RESTful application in Java using Spring boot by following the tutorial here. I want to modify it so that I can extract an identifier from the URL and use it to serve requests.
So http://localhost:8080/members/<memberId> should serve me a JSON object with information about the member whose ID is <memberId>. I don't know how to
Map all http://localhost:8080/members/* to a single controller.
Extract the from the URL.
Should the logic of extracting the memberId and using it be part of the controller or a separate class, as per the MVC architecture?
I am new to Spring/Spring-boot/MVC. It is quite confusing to get started with. So please bear with my newbie questions.
Map all http://localhost:8080/members/* to a single controller.
You can use a placeholder in a request mapping to so it'll handle multiple URLs. For example:
#RequestMapping("/members/{id}")
Extract the id from the URL
You can have the value of a placeholder injected into your controller method using the #PathVariable annotation with a value that matches the name of the placeholder, "id" in this case:
#RequestMapping("/members/{id}")
public Member getMember(#PathVariable("id") long id) {
// Look up and return the member with the matching id
}
Should the logic of extracting the memberId and using it be part of the controller or a separate class, as per the MVC architecture?
You should let Spring MVC extract the member id from the URL as shown above. As for using it, you'll probably pass the URL to some sort of repository or service class that offers a findById method.
As you can see in the code below, service for customer are in one controller to get one and to add new customer.
So, you will have 2 services:
http://localhost:8080/customer/
http://localhost:8080/customer/{id}
#RestController("customer")
public class SampleController {
#RequestMapping(value = "/{id}", method = RequestMethod.GET)
public Customer greetings(#PathVariable("id") Long id) {
Customer customer = new Customer();
customer.setName("Eddu");
customer.setLastname("Melendez");
return customer;
}
#RequestMapping(value = "/{id}", method = RequestMethod.POST)
public void add(#RequestBody Customer customer) {
}
class Customer implements Serializable {
private String name;
private String lastname;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
public String getLastname() {
return lastname;
}
}
}

Entity Framework / MVC Remove Item from Collection

What are some ways I can delete an item from a collection? (I am using MVC 4 and EF.)
As an example:
public class Birthday
{
public string Name { get; set; }
public virtual ICollection<Gift> Gifts { get; set; }
}
public class Gift
{
public string Name { get; set; }
public double Price { get; set; }
}
I'm using Editing a variable length list, ASP.NET MVC 2-style to create a dynamic list of Gifts.
The example is shows how to "Delete" a row. This will delete the row from the page and the correct Gifts are sent to the controller.
When I update the Birthday / Gifts everything new is updated properly, but anything deleted is still there.
So my question is what are some preferred ways to remove Gifts?
Two ways I've thought of already:
Get a Birthday from the DB and compare the Gifts removing as needed. I don't love this idea because it seems heavy handed.
Use WebApi / Ajax and delete the Gift from the list and the DB when the user pushes the delete link. I like this better than #1 but does this put too much business logic in the presentation layer?
I'm guessing that other people have had this similar problem and have a clever solution I haven't thought of yet.
Thanks in advance!
Make a Gifts api controller.
Let it have a Delete method accepting an Id of whatever type your Id is.
And do something like this in it:
public class GiftsController: ApiController
{
public void Delete(Guid Id)
{
var context = new MyContext();
var giftToDelete = context.Gifts.FirstOrDefault(g=> g.Id == Id);
if(giftToDelete != null)
{
context.Gifts.Remove(giftToDelete);
context.SaveChanges();
}
}
}
Make sure you make a DELETE request to this api in your JS delete function.
You may also replace the body of this method with some Service.DeleteGift(Id) if you're too concerned about doing things in the right place.
Like this:
public class ValuesController : ApiController
{
private List<string> list = new List<string>{"Item1","Item2","Item3","Item4","Item5"};
// DELETE api/values/5
public List<string> DeleteItem(int id)
{
list.Remove(list.Find((i => i.ToString().Contains(id.ToString()))));
return list;
}
}

MVC4 and Entity Framework Inheritance and Include

I have some simple objects
public class DataClass
{
public int id;
public string Data;
}
public class Job()
{
public int id;
}
public class NewJob : Job
{
public DateTime StartDate;
public DataClass data;
}
I have then defined them in my dBContext()
public DbSet<Job> Jobs { get; set; }
public DbSet<DataClass> DataClass { get; set; }
Now if I use the following code
NewJob job = (NewJob) db.Jobs.Find(id);
This works fine but returns "data" as null
I know I define the class with the virtual keyword and it works and populates the "data" object.
public class NewJob : Job
{
public DateTime StartDate;
public virtual DataClass data;
}
But in my case I "normally" do not want the "data" object to be populated. So I need to load it on demand.
If I try something like
NewJob job = (NewJob)db.Jobs.Include("data").First();
I get an exception
A specified Include path is not valid. The EntityType 'Models.Job' does not declare a navigation property with the name 'data'.
I guess this is because it is looking at "job" and not "NewJob" when it is trying to do the include.
I also do not like the include with a string - no design time checking.
It looks like you are trying to convert data object to your domain object via type casting which is a very bad idea. What you want to do is grab your data object, instantiate your domain object, and map your data values to the domain object using some type of helper class. A very helpful tool I have been using is Automapper. Its a tool that will allow you to map one object to another. It also allows the use of regular expression to help with the mappings if the naming conventions between the 2 objects are different.
If you're using Entity Framework Code First and want to create instances of derived classes/entities you should do the following:
using (var db = new MyDbContext())
{
var newJob = db.Jobs.Create<NewJob>();
newJob.data.Data = "some data for a new job"; // this is string Data from DataClass
db.Jobs.Add(newJob);
db.SaveChanges();
}
After a lot of searching I found the following which can help.
If you include the System.Data.Entity namespace in your using clause then you can use the extension method .Include() after OfType<>() which is not normally available.
Slightly different code sample
using System.Data.Entity;
NewJob job = (NewJob)db.Jobs.OfType<NewJob>().Include(m => m.data).Where(x => x.id == id).FirstOrDefault();
This seems to be working for me in the example I used.

Coding Style: Is it acceptable to make further queries from within model classes?

I have a model class Alert with a one-to-many relationship with another model class Occurrence, as follows:
#Entity public class Alert extends Model
{
public String name;
#OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY, mappedBy="alert")
public List<Occurrence> occurrences;
}
#Entity public class Occurrence extends Model
{
#ManyToOne
public Alert alert;
#Column(nullable=false)
public Date alertTime;
}
I have a view that lists Alerts in a simple table, which should have a column labelled "Occurrences today", with a count of how many occurrences of the alert have happened today (by alertTime).
I can't seem to find a way to do this using only JPA/Hibernate annotations in the Alert model class, and since I am listing Alerts, I don't know of a clean way to include the count in each Alert object.
So now I am wondering if it would be fine to simply query for the alert's occurrences from within the Alert model class itself, like so:
#Entity public class Alert extends Model
{
public String name;
#OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY, mappedBy="alert")
public List<Occurrence> occurrences;
#Transient
public long getOccurrencesToday()
{
return Occurrence.count(
"alert = ? and alertTime >= ?",
this, new DateMidnight().toDate());
}
}
My question is: Is it considered bad form to make queries to the DB from within a model class?
A secondary question is: Am I approaching this the wrong way? Is there a better way to achieve the end result that I've missed?
making queries from within domain model class should be the correct way to go giving those queries are relevant to that model. To this end, I don't see any problem with your code.
From Play's philosophy, domain object is not merely a data object. It should enclose certain business logic inside. In fact pure data object is not encouraged by play. Check more on http://www.playframework.org/documentation/1.2.4/model
While your approach is tempting, its dangerous because effectively you're putting logic into a "getter" (getOccurrencesToday()) which you'll probably access by ${alert.occurrencesToday}
A getter should always be side effect free.
I would change this to
#Entity public class Alert extends Model
{
public String name;
#OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY, mappedBy="alert")
public List<Occurrence> occurrences;
#Transient public Long occurrencesToday = null;
public void populateOccurrencesToday()
{
occurrencesToday = Occurrence.count(
"alert = ? and alertTime >= ?",
this, new DateMidnight().toDate());
}
}
then in your controller, iterate over all alerts that
you're going to render and execute the populateOccurrencesToday() method.
If you're now storing your object in a cache, its data will be consistent.

DDD, Entity Framework, Aggregate Entity Behavior ( Person.AddEmail, etc)

Here's a simple example of a problem I'm running across that is not meshing with some of the ideas presented here and other places regarding DDD.
Say I have an ASP.NET MVC 3 site that creates/manipulates a person. The controllers access an application service layer (PersonService) which in turn uses the domain entities (EF 4 POCO) and the PersonRepository to make changes and persist them. I'm leaving out all interfaces here for simplicity. Person is the root in this case and for simplicity only has email addresses (also assume email is not immutable and can be updated).
Option 1:
Try to stick with [my understanding] of the basics of DDD where behavior directly related to the entity is implemented as part of the entity (Person implements AddEmail, ChangeEmail, etc). The only problem with this, with the exception of the Add* methods, is that the Person would need to know about the context or entity framework pieces (which would remove any persistence ignorance) or need to use a "service" or repository to mark the email as modified.
// Person Service
public class PersonService {
// constructor injection to get unit of work and person repository...
// ...methods to add/update a person
public EmailAddress AddEmailAddress(int personId, EmailAddress email)
{
Person p = personRepository.Find(p => p.Id == personId).First();
p.AddEmail(email);
uow.SaveChanges();
return email;
}
public EmailAddress ChangeEmailAddress(EmailAddress email)
{
Person p = personRepository.Find(p => p.Id == personId).First();
p.ChangeEmail(email);
// change state of email object here so it's updated in the next line???
// if not here, wouldn't the Person entity have to know about the context
// or use a service?
uow.SaveChanges();
return email;
}
}
// Person Repository
public class PersonRepository
{
// generic repository implementation
}
// Person Entity
public class Person
{
public string Name { get;set; }
public IEnumerable<EmailAddress> EmailAddresses { get;set; }
public void AddEmail(EmailAddress email)
{
this.EmailAddresses.Add(email);
}
public void ChangeEmail(EmailAddress email)
{
EmailAddress orig = this.EmailAddresses.First(e => e.Id == email.id);
// update properties on orig
// NOW WHAT? [this] knows nothing about the context in order to change state,
etc, or do anything to mark the email add updated
}
}
// Email
public class EmailAddress
{
public string Email { get;set; }
public bool IsPrimary { get;set; }
}
Option 2:
Let the person service use the repository to add/update the email address and don't implement the behavior on the person entity. This is much simpler in the case of many to many relationships (for example, address, where two tables need to be updated to complete the work) but the model then becomes 'anemic' being just a bunch of getters and setters.
// Person Service
public class PersonService {
// constructor injection to get unit of work and person repository...
// ...methods to add/update a person
public EmailAddress AddEmailAddress(int personId, EmailAddress email)
{
Person p = personRepository.Find(p => p.Id == personId).First();
personRepository.AddEmail(personId, email);
uow.SaveChanges();
return email;
}
public EmailAddress ChangeEmailAddress(EmailAddress email)
{
personRepository.ChangeEmail(email);
uow.SaveChanges();
return email;
}
}
// Person Repository
public class PersonRepository
{
// generic repository implementation
}
// Person Entity
public class Person
{
public string Name { get;set; }
public IEnumerable<EmailAddress> EmailAddresses { get;set; }
}
// Email
public class EmailAddress
{
public string Email { get;set; }
public bool IsPrimary { get;set; }
}
Anyway, any thoughts on this?
Thanks, Brian
Option 1 is the way to go.
Reasoning is simple - changing e-mail addresses is domain concern. I bet Your domain experts have said that they will need to change emails. That automatically marks email changing piece of logic as business logic which is supposed to live in domain model. Objects primarily are defined by their behavior and not data that they hold.
Also - think twice before You choose to use unit of work pattern and wrap around everything in services. Aggregate roots are supposed to draw transaction boundaries and services usually are useless if they just wrap repository and domain object calls.
I would have something like this:
public class Person{
public Email Email{get;private set;}
public void SpecifyEmail(Email email){
//some validation, if necessary
EnsureEmailCanBeChanged();
//applying state changes
Email=email;
//raising event, if necessary
Raise(new EmailChanged(this));
}
public class EmailChanged:Event<Person>{
public EmailChanged(Person p):base(p){}
}
}
public class Email{
public Email(string email){
//validations (e.g. email format)
Value=email;
}
//implicit to string, explicit from string conversions
}
public class PersonController{
public ActionResult SpecifyEmail(int person, string email){
_persons.Get(person).SpecifyEmail((Email)email);
return RedirectToAction("Person",new{person});
}
}
I'm using NHibernate - it's smart enough to figure out what has changed since Person was persisted last time. Hard to say how exactly entity framework handles this.
I'm an NH user and may not know all EF limitations but generally speaking, whatever the limitations of ORM, entities should be left as clean as possible. Service Layer is already coupled with Data Access so no harm's done.
And I believe EF4 should know how to track collection changes. If not, then the best way is to leave the adding/removing logic in your Person entity and persist in PersonService.
BTW, your EmailAddress isn't an entity here, no Id (just a typo I guess). And how do you link your EmailAddress to Person?