Validate instance of domain class is unique - grails

I have a Grails application with a bunch of domain classes, some with many fields, some of which have a hasMany relationship with the domain class in question. For this particular application I only have one "constraint", that is that every instance of every domain class must be unique. I don't care if an arbitrary field has the same value across multiple instances of the same domain class, so long as each instance is made unique by the value of some other field in that domain class. So basically I want validation to take place at a domain class instance level instead of the domain class field level. Right now I am doing that by using the very groovy #EqualsAndHashCode annotation to generate my equals and hashCode methods, then calling equals in a custom validator on some arbitrary field of a domain class.
Two questions:
Is there a more efficient way of validating a domain class is unique?
If no, then is there a way I can call my custom validator code on the domain class instance itself instead of going through one of the fields of the domain class instance?
#groovy.transform.EqualsAndHashCode
class MyDomainClass {
String some
int arbitrary
boolean field
static constraints = {
// The field I chose to validate on is irrelivant, I just need to run the validation code **somewhere**
arbitrary validator: { val, obj ->
return !MyDomainClass.getAll().contains(obj)
}
}
}
I should also add I'm looking for a generic (hopefully efficient) way to do this. I realize calling getAll() is very inefficient and instead calling some variant of find or performing an HQL query on the exact fields of each domain class would be much more efficient... it just takes a lot longer to write!
Examples
assert MyDomainClass.getAll().isEmpty() // true
def myDomainClass1 = new MyDomainClass( some: "foo", arbitrary: 1, field: true)
assert MyDomainClass.getAll().contains(myDomainClass1); // false
myDomainClass1.save(flush:true)
def myDomainClass2 = new MyDomainClass( some: "bar", arbitrary: 1, field: true)
assert MyDomainClass.getAll().contains(myDomainClass2); // false. Even though this has the same `arbitrary` value as myDomianClass1, it has a different `some` value which makes it unique.
myDomainClass2.save(flush:true)
def myDomainClass3 = new MyDomainClass( some: "foo", arbitrary: 1, field: false)
assert MyDomainClass.getAll().contains(myDomainClass3); // false. Even though this has the same `some` value as myDomainClass1 and the same `arbitrary` value as myDomainClass1 and myDomainClass2, it has a different `field` value which makes it unique.
myDomainClass3.save(flush:true)

This will ensure the combination of the 3 fields in the domain are unique. This also ensures the constraint is on the database level, instead of just application level.
class MyDomainClass {
String some
int arbitrary
boolean field
static constraints = {
some(unique: ['arbitrary', 'field'])
}
}

Related

Grails GORM Inheritance changing discriminator column

I'd like to use an Enum or String in place of column class to map on table inheritance in Grails.
For exemple
#Entity
#Table(name = "person")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorValue("USR")
#DiscriminatorColumn(length = 3, discriminatorType = DiscriminatorType.STRING, columnDefinition = "CHAR(3) NOT NULL", name = "type")
public class People implements Serializable {
I couldn't find a way to change it into documentation.
Going to try to answer your question but in all honesty unsure where your point is wavering towards since it is left open ended as to to the actual question raised Inheritance and there appears to be no signs of inheritance on example provided.
My first pointer would be here.
This does work or had it working on default grails 3.2.8 but upon updates to latest gorm there was issues with updating existing records. I gave up and did it as separate classes at the time.
If your question relates to having table per class then above setup is what you need for grails.
Typically you would do :
abstract class Something {
static mapping = {
cache true
//tablePerConcreteClass false
tablePerHierarchy false
//discriminator value: 'institution'
}
}
class SomethingElse extends Something {
static mapping={
//discriminator value: 'somethingElse'
}
}
The abstract class definition vs non abstract has different adverse effects into how your tables get created and how your whole model will then work. It all depends on the requirement.
The problem with above is when it comes to querying the class in HQL I faced a problem where when I tried to query instance.class I got a numeric number back from HQL rather than actual domainClass instance and obviously discriminator was first point of reach.
The actual trick in these extended classes is if in HQL something.class does not return actual class name to try
String query = """ select new map(type(s) as className,s.id as id) from Something s """
The type(s) will now return actual string class name. (Maybe where you are stuck)
Usually you can do in HQL:
when s.class = SomethingElse then do something
and HQL will work out the actual className based on that matching domainClass name.
Somehow I don't think this is what you are after though

What is best way to update domain class object with large number of variables

Suppose I have Employee domain class, I want to create object of domain class from params map coming from UI side.
I can create object in two ways as follows
Normal way
Employee employee = new Employee(name: params.name, rollNo:
params.rollNo)
and so on. If domain class has 20 variables, then we need to write all variables in above constructor.
Following is best way to create object
Employee employee = new Employee(params)
Above constructor will populate object with matching params. Right.
Now my question comes here.
If suppose I have existing domain class object fetched from DB, Now I want to update this object from params map coming from UI.
What is best way to do this (like we do in above second option).
I think it is best to use command objects and bind it to the Employee.
here is sample pseudo code:
class EmployeeMgmtController {
def editEmp(EmployeeCmd cmd){
Employee editEmp = Employee.get(1)
editEmp.properties = cmd
editEmp.save()
}
}
class EmployeeCmd{
String id
static constraints = {
id blank:false,nullable:false
}
}
or,
you if your on controller, and still want to use params (and exclude any fields that you don't want to bind):
bindData(editEmp, params, [exclude:['firstName', 'lastName']])
If you want to achieve that in a service class, make your service implement grails.web.databinding.DataBinder then use the bindData method as demonstrated below.
import grails.web.databinding.DataBinder
class MyAwesomeService implements DataBinder {
/**
* Updates the given instance of a domain class to have attribute values specified
* in "newData" map.
*/
MyDomain updateMyDomainAttributes(MyDomain myDomianInstance, Map newData) {
bindData(myDomianInstance, newData)
myDomianInstance.save(flush: true)
}
}

Grails binding one to one associations

When you generate grails views, grails looks at your relationships and generates the right html for your form data to be automatically binded to the back end domain. For one to one associations grails creates a drop down list.
However, you might not want to present that property as a drop down list but something more custom (for example a text field with autocomplete). As soon as you do that the value that comes to the controller from that field, comes in as a String and you have to first:
Clear errors
Perform a findBy based on a given param and assign it to the property of the domain
I really want to avoid doing findBys in the controller as much as possible because it seems like I am doing logic/things that should not go there. The controller should delegate to the Service layer. It is not clear to me from the grails documentation how would I do that by using bindData which seems to work really well with String, date, Integer properties etc.. but I do not see how bindData is used for properties that are other domains.
I also really want to avoid passing the params object to the Service layer as it seems less reusable (or maybe not, correct me if I am wrong). I guess that I do not like how it looks semantically. I would prefer the first over the second:
#Transactional
class WithdrawService {
def addWithdraw(Withdraw withdraw) {
//perform business logic here
}
def createWithdraw(Map params){
//perform business logic here
}
}
Let's take the following example:
class Withdraw {
Person person
Date withdrawDate
}
and the parent lookup table
class Person {
String name
String lastName
static constraints = {
}
#Override
public String toString() {
return "$name $lastName"
}
}
In order for the bind to happen automatically without any extra work grails passes in the following request params to automatically bind the one to one:
person.id
a person map with the id.
[person.id:2, person:[id:2], withdrawDate:date.struct, withdrawDate_month:11, create:Create, withdrawDate_year:2015, withdrawDate_day:10, action:save, format:null, controller:withdraw]
What is the best way to go about this?
Pass two hidden fields that look exactly like this: person.id:2, person:[id:2] that get populated as a result of the Ajax call that populates the autocomplete?
In the controller do a Person.findBySomeKnownProperty(params.someKnownValue)
Or any other approach?

Validation Method in Domain Class

I inherited an app from a consultant, and am trying to follow the code that finds a user from the database via two parameters - Providier and Identifier.
From what I gather, there is a controller method, which in turn calls a service method, and that service method calls what appears to be a validator in the domain class called Login.
I feel like I have reached a dead-end here. Where would I expect to find the actual code for Login.findByProviderAndIdentifier()?
class Login {
String id
String identifier
String password
boolean generated = false
Provider provider
Date lastUpdated
Date dateCreated
Boolean isActive = true
static constraints = {
identifier(blank:false,
validator: {val, obj, errs ->
if (val && obj.provider && !obj.generated) {
def dbLogin = Login.findByProviderAndIdentifier(obj.provider, val)
if (dbLogin && dbLogin.id != obj.id) {
errs.rejectValue("identifier", "unique", [obj.provider.name, obj.identifier] as Object[], "Identifier ${obj.identifier} already exists for provider ${obj.provider.name}")
}
}
}
}
This method is a dynamic finder. The "actual code" for it is generated on the fly by GORM. The way the documentation describes it is:
GORM supports the concept of dynamic finders. A dynamic finder looks
like a static method invocation, but the methods themselves don't
actually exist in any form at the code level.
Instead, a method is auto-magically generated using code synthesis at
runtime, based on the properties of a given class.
So in this case GORM creates a select statement with a where clause that takes a provider id and the identifier value that's being validated.
If you want to see the generated query you can turn on Hibernate SQL logging, or set up log4jdbc.

Make a required class properties not required

I have a class set up to hold values on a registration form (VB.NET, MVC), and among the properties is a Password property:
Public Class RegisterModel
...
Private _password As String
<DisplayName("Password:"), Required(), ValidatePasswordLength(), DataType(DataType.Password)> _
Public Property Password() As String
Get
Return _password
End Get
Set(ByVal value As String)
_password = value
End Set
End Property
This works great when registering a new user, but I'd like to use the same class to update existing users. (Note: this app is run by an admin who is in charge of registering individuals and assigning passwords.) The way I'd like it to behave is if the admin leaves the password blank, then the password is not changed, but the rest of the information is. If I use this class, the password can't be left blank because it fails on the Required() and ValidatePasswordLength() calls.
Is there a way to use this class but tell the model to ignore these particular validations? Even if I leave the password field off my edit form, it still fails. Do I need to create a whole duplicate class without these restrictions on the password field? There must be a better way.
You could implement IDataErrorInfo and have a flag set on the model which indicates whether it is being used by an admin or not - you could then validate conditionally.
But overall, I'd say this is a bit of a code smell. You're using a model for two different, incompatible purposes. It'd be better to use a separate view model.
I'd recommend using the FluentValidation library. It's a fantastic way to separate the concerns of your view (view model) and the actual validation you want to perform. You could pass parameters into it to drive different behavior. Check out When/Unless conditions or just writing completely custom validation methods with the Must operator.
public class RegisterModelValidator: AbstractValidator<RegisterModel>
{
public RegisterModelValidator(bool isAdmin)
{
RuleFor(x => x.Password).NotEmpty().Unless(isAdmin);
...
}
}
As long as your view model would have identical properties in both scenarios, you should use the one view model and one validation class. If the model varies at all I'd use two view models as David recommends.
You can do this in 2 ways:
1: add the [ValidateInput(false )] attribute to the action
or
2: Add a new property to the Register Model
public bool IsNewUser {get;}
3: Create a new class level attribute that takes IsNewUser into account when validating

Resources