How to submit a form that has data for 2 models on Spring and let it validate them? - spring

Suppose I have 2 tables: users and preferences.
users table has columns username, password and email.
preferences table has columns contact_me_by_email, contact_me_by_phone_call, contact_me_by_sms.
Each table has it's own model (User and Preferences).
I want to present just one page for users so that when they fill in data in the form that data will be validated and will populate both tables.
I'm able to get all parameters from one form by accessing the Request object and manually performing all validations and proceed according to the results I get.
Also, I can successfully use #Validate annotation to validate models when I present 2 pages for user (each page having just one model - first page contains only data for User model and the second one contains only data for preferences).
I'm struggling to discover a way to present one page only with a form that contains all fields from both models above that could be validated by Spring using the #Validate annotation.
Is that possible? Is there any other annotation I'm not aware of that could do it?
Any help is very much appreciated.
Regards.

So, here is your user mode class :
#Entity
#Table(name = "user")
public class User(){
// Fields of your user annotated with #Column
and fields of your preferences annotated #Transient as below :
#Transient
private String favoriteTvShow;
//getters and setters for both
}
This way you need to submit only one form. Enjoy.

Related

asp.net core Identity user customization

Detail
I am developing web application in asp.net core with Identity. now in my application I have two kind of user. Customer and Partner both have different profile information and login scenario.customer can login from simple signup from web page but partner can signup from different view with different mandatory fields.
Problem
How can I design Schema.
what are the good practices in this case.
What are the drawback.
Code
This is what I have done so far
public class ApplicationUser : IdentityUser
{
public CustomerProfile CustomerProfile { get; set; }
}
Use inheritance:
public class ApplicationUser : IdentityUser {}
public class Customer : ApplicationUser
{
// Customer-specific properties
}
public class Partner : ApplicationUser
{
// Partner-specific properties
}
By default, this will be implemented via STI (single-table inheritance). That means you'll have just your standard AspNetUsers table containing columns for the properties on ApplicationUser and all derived types. A discriminator column will be added to indicate which type was actually saved, which will then be used to instantiate the right type when queried.
For the most part, this works just fine. The one downside is that properties on derived classes must be nullable. The reason is simple: it would be impossible to provide values for Customer columns while saving a Partner and vice versa. However, the properties only need be nullable at the database-level. You can still require that they be set in forms and such via a view model.
The alternative is to use TPT (table-per-type). With this approach, you'll get AspNetUsers, but also Customers and Partners tables as well. However, the tables for the derived types will have columns corresponding only to the properties specific to that type and a foreign key back to AspNetUsers. All common properties are stored there. With this, you can now enforce columns have values at the database-level, but querying users will require a join. To use TPT, you simply add the Table attribute to your class, i.e. [Table("Customers")] and [Table("Partners")], respectively.
The one important thing to keep in mind with using inheritance, though, is that you need to work with the type you actually want to be persisted. If you save an ApplicationUser instance, it will be an ApplicationUser, not a Customer or Partner. In this regard, you need to be careful with using the correct types with things like UserManager which generically reference the user type. Even if you create an instance of Customer, if you save it via an instance of UserManager<ApplicationUser>, it will upcast to ApplicationUser and that is what will be persisted. To create a new Customer, you'll need an instance of UserManager<Customer>. Likewise, for partners.
However, this also works to your benefit, as if you attempt to look up a user from an instance of UserManager<Customer> for example, you will only find them if they are in fact a Customer. In this way, it makes it trivially simple to have separate portals where only one or the other can log in, as you've indicated that you want.

is it possible to have conditional #Transient field?

Let's say if I have an Entity named person with lots of information including SSN. When other user query this person, I want to show a 'lite' version of person Entity. I could've done so by annotating SSN with #Transient, but that means the person himself would not get this field too. Is it possible to reuse the same Entity but return two different json to client? I'm using spring boot.
First of all #Transient just means that the value, the SSN in your case, won't be persisted to the database.
As for your problem annotations are static and cannot be applied dynamically.
You have 2 Options:
Define a new View class for your user.
Look at JacksonJsonViews

how to make a spring jpa/correct repository when having mandatory relationships?

I have the following database which allows users to rent books in a book shop:
The entity class Book needs to have a Category as well as BookDescription when saved.
Those Book class looks like this:
#Entity
#Table(name = "books")
#Inheritance(strategy = InheritanceType.JOINED)
public abstract class Book {
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name = "book_description_id")
private BookDescription bookDescription;
#ManyToOne(cascade = CascadeType.PERSIST, fetch = FetchType.LAZY)
private Category category;
//omitted fields, getters, setters & other relations
}
I was checking out Spring Data JPA. It has a signature of
CrudRepository<T, ID extends Serializable>
which means that I will have
CrudRepository<Book, String>
but how will I save a book?
So, generally, the user will submit a form, I will bind a BookUIObject which will contain all the details needed to save a book, pass it to a BookService witch will extract from it 3 objects: Book ( a specific implementation), Category and BookDescription. The question is will the service hook up the book relations and call the general repository.save(Book) or it will call a method like repository.save(Book, Category, BookDescription)?
Also, should I bind directly the data from the user into entity classes, or do like I said, bind to a general BookUIObject and let the service extract from it the entity classes?
Kind regards,
Typically you will have to call BookReporitory.save(book). Book has cascaring Persist for both of the relations, so if you have set the BookDescription and the Category on the book instance you save, they will also be persisted. If you didn't have cascading persist, you would have to save them using their JPARepository (unless they already existed in the Persistence context).
One thing that is important to understand in this example is that if you create a new category object and set it on a book and save the book a new category is created in the DB. So if the UI posts category=sic-fi, you have to check if the category already exists, if it does then you must used the managed category, and set that on the book rather than creating another "sci-fi" category. This is the reason I would not have cascading persist on the Category relation, because I would rather have a constraint violation because a category didn't exist, instead of an new category sci-if when someone miss spelled it in the UI.
I do not recommending binding forms directly to JPA entities, because you always need to fetch entities from JPA, as you have to use the managed versions, so in my experience it is better to have another set of beans for form binding.
Another thing that jumps out if the lack of nullable=false in #JoinColumn. If a book can't exist without being in a Category it is vital that this is communicated to the database, and if you generate tables from the JPA metadata model, this is how it is done. If I could give only one recommendation when working with databases/JPA it is to be overzealous with NOT NULL. It is a 100 time easier to get a constraint violation when you insert, than to get a NullPointerException later and have to check every possible code-path that could end up calling save and checking if the argument could be null.
In addition I would recommend that you set of some time to understand the concept of the EntityManager and the Persistence Context, most of the mistakes/assumptions developers make come back to the persistence context and how the 4 entity states work.

Signup, Edit personal and Modify password forms in Spring MVC

Spring MVC, Signup, Edit personal and Password forms
My Spring MVC application is a website where members can subscribe to indoor and outdoor activities, organized by a member. THe application therefore needs a well-known funcionality to sign up, login and edit/modify personal details.
I used Spring MVC in combination with Thymeleaf views. THis works fine but I am struggling with the different forms and try to avoid redundant fields.
The following use cases are required:
Sign up:
User chooses a username, password en password confirmation and personal details like birth date, gender, city, personal interests.
After submitting the form, form validation checks whether username is not in use and passwords fields are equal.
Edit personal data:
When logged in, the user can choose to edit his/her personal data. Username cannot be changed (and is therefore invisible or at least immutable in this form) and password fields are not shown.
Edit password;
To change the password, the logged in user enters his existing password for extra security, and the new password and the confirmation of the new password. After committing, the existing password is verified and changed afterwards if and only of the new password and confirmation are matching.
I think this is pretty common functionality. But my issue is that we have only one Member class that can act as the form-backing object (The Spring MVC documentation advises against the use of separate form backing objects).
Besides, the password is not stored as the plain entered text, but as the (SHA-256) hash.
For the signup use case, I choose the following approach:
THe Member entity object contains one mapped field for the hashed password (which is persisted in the database) and two transient fields for entering the password which are bound to the form and validated for being equal and match other criteria (minimum length, special characters etc):
#Entity
#Table(name="member")
public class Member {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Size(min=3, max=25)
#Column(name = "loginname", nullable = false, updatable = false)
#NotEmpty
private String loginName;
#Transient
private String registerPassword;
#Transient
private String retypeRegisterPassword;
#Column(name = "password_sha256", nullable = false, updatable = false)
#NotEmpty
private String passwordHash;
... more fields, getters and setters
In the intitial signup form, the new user enters his username, password (Twice) and all other required fields. This works as expected.
But what if the user wants to edit his personal data?
We do not want to edit the username and password fields in this scenario. The other fields need to be validated according to the same rules as the signup form. So we should need:
1) A separate form backing object, mimicking the Member object but without username and password fields. This sounds unacceptable to me due to redundancy.
2) Or use the same form backing object but somehow bypassing the username and password fields in the validation. Of course, those fields must be preserved when saving the member object back to the database using Hibernate, but we can make a customized update method in the service layer to handle that.
And the last use case is modifying the password. For this I want a separate form with 3 fields, the original password for extra verification and two fields for the new password and its confirmation.
I think I should use a separate form backing object for this containing only those 3 fields, but do not want to duplicate the field and validation definitions.
Is there a clean way to do this without redundant definitions?
Hope for some thoughts... :)

.NET MVC 3 Validation

I use Entity framework for creating model.
I have table hierarchy where User is my base table and I have tables Lecturer and Student which have some specific data in them. Entity framework made model that it isn't suitable so I made my middle layer called modelview where I have student table which wraps all data from both user and student tables. I have made CRUD functionality for students but I only want that admin can create student with some initial password, than admin should not have option to change student password at Edit action.
The problem is that password is required field at student Create action so I set [Required] attribute to it, but at Edit I must not have password field and my ModelState.IsValid is then always false since password field in this case isn't present and therefore is null.
I thought on adding hidden password field, but that would be very bad since someone could look at page source and see password value.
Can I somehow once this field required and another time not required?
If you have any other idea that might help please share with me.
When a user is being edited, you can put in a placeholder hidden field, with the value * (or something like that). This will satisfy the Required attribute - you just have to make sure you don't update the password when the user is edited :)
Maybe you could randomly generate a password and not have it be required at all.
Or you could remove the requred attribute and manually check if it's present at the serverside.
if (string.IsNullOrEmpty(user.Password))
ModelState.AddModelError("Password","A password is required");
To validate clientside, if you're using jquery validation: JQuery Docs
If you have separate views for Student addition and editing, an alternative solution would be:
Create a StudentViewModel class which contains all the properties required for both Student addition and editing, and
Create a StudentAdditionViewModel class (optionally derived from StudentViewModel) which includes a Password property.
You can then use StudentAdditionViewModel as the Add view's model, and StudentViewModel as the edit view's model :)

Resources