I have problem with a setter in grails. I have two properties beforeTax and afterTax. I only want to store one property in the db beforeTax. In the ui I want the user to enter either before or after tax. So I made the afterTax a transient property like this:
double getAfterTax(){
return beforeTax * tax
}
void setAfterTax(double value){
beforeTax = value / tax
}
When I now enter the after tax value and want to save the object the validation fails (before tax can not be an empty value)
What am I doing wrong?
If I understand your question correctly, you want to compute beforeTax based on the value of afterTax?
You could use the event handler methods beforeXXX() where XXX is Validate, Insert, and Update to compute beforeTax. Then beforeTax's constraint can be nullable:false.
def beforeValidate() {
computeBeforeTax()
}
You have to flag one property as transient, in order to prevent GORM from trying to save this variable into DB. Try to add this line into your domain class, which contains afterTax.
static transients = ['afterTax']
Related
I have an apex trigger (before insert/update) and a helper class to that trigger. The problem is: When creating an object record, the trigger should check if the AddedDate field is filled and if it's not - then assign it today's date and current time.
And when I create and update a Product object record, the trigger must check the length of the Description field, if the field is longer than 200 characters, I must trim it to 197 characters and add a triple to the end of the line.
What am I doing wrong and how should I proceed?
My trigger:
trigger ProductTrigger on Product__c (before insert, before update) {
if(Trigger.isUpdate && Trigger.isAfter){
ProductTriggerHelper.producthandler(Trigger.new);
}
}
Trigger helper class:
public class ProductTriggerHelper {
public static void producthandler(List<Product__c> products) {
Schema.DescribeFieldResult F = Product__c.Description__c.getDescribe();
Integer lengthOfField = F.getLength();
//List<Product__c> prList = new list<Product__c>();
for(Product__c pr: products){
pr.AddedDate__c=system.today();
if (String.isNotEmpty(pr.Description__c)) {
pr.Description__c = pr.Description__c.abbreviate(lengthOfField);
}
}
}
}
According to your requirements
When creating an object record, the trigger should check if the AddedDate field is filled and if it's not - then assign it today's date and current time.
You aren't doing that.
Change pr.AddedDate__c=system.today(); to
if (pr.AddedDate__c == null) { pr.AddedDate__c=system.today(); }
Also according to the abbreviate function documentation the parameter it takes is the max length including the 3 elipses.
So change pr.Description__c = pr.Description__c.abbreviate(lengthOfField); to
pr.Description__c = pr.Description__c.abbreviate(200);
To add to Programmatic's answer...
You defined the trigger as before insert, before update. Cool, that's perfect place for doing data validations, field prepopulation... And you'll get save to database for free!
But then this clashes with next line if(Trigger.isUpdate && Trigger.isAfter){. With this setup it'll never fire. Either remove the if completely or (if you think trigger can get more events in future) go with trigger.isBefore && (trigger.isInsert || trigger.isUpdate).
P.S. It's datetime field? So pr.AddedDate__c=system.now(); is better
I don't understand why it is recommended everywhere to use AddOrUpdate in the Seed method?
We develop application for half a year already and the AddOrUpdates overwrites user changes every time we update the server. E.g. if we call in the Seed:
context.Styles.AddOrUpdate(new Style { Id = 1, Color = "red" });
And user changes the Style to "green" then on next server update we overwrite it to "red" again and we get very annoyed user.
It looks that if we change AddOrUpdate to Add we will be guaranteed from overwriting user data. If we still need some special case we can put it to separate migration. Unlike the general Configuration.Seed method particular migrations don't run twice over the same database version.
I assume that Style's primary key is Id. The overload of AddOrUpdate that you use only checks if there is a record having Id == 1. If so, it updates it. That's all.
What's going wrong here is that the primary key is a surrogate key, i.e. it's there for querying convenience, but it's got no business meaning. Usually, with migrations you want to look for the natural keys of entities though. That's how the user identifies data. S/he wants a green style, not a style identified by 1.
So I think you should use this overload of AddOrUpdate:
context.Styles.AddOrUpdate( s => s.Color,
new Style { Id = 1, Color = "red" });
Now when there is no red style anymore, a new one is inserted, overriding the Id value (assuming that it's generated by the database).
From your later comments I understand that you want to Add data when they're new, but not update them when they exist (compared by primary key). For this you could use a slightly adapted version of an AddWhenNew method I described here. For your case I would do it like so:
public T void MarkAsAddedWhenNew<T>(this DbContext context,
Expression<Func<T, object>> identifierExpression, T item)
where T : class
{
context.Set<T>().AddOrUpdate(identifierExpression, item);
if (context.Entry(item).State != System.Data.Entity.EntityState.Added)
{
var identifierFunction = identifierExpression.Compile();
item = context.Set<T>()
.Local
.Single(x => identifierFunction(item)
.Equals(identifierFunction(x)));
context.Entry(item).State = System.Data.Entity.EntityState.Unchanged;
}
return item;
}
Re-fetching the item from the local collection is a nuisance, but necessary because of a bug in AddOrUpdate(). This bug also caused the error you got when setting the state of the original entry to Unchanged: it was a different instance than the attached one.
The way Add method acts is misleading. It Inserts data into database even if there is already a row with the same PrimaryKey as we do Add. It just creates new PrimaryKey ignoring our value silently. I should have tried it before asking the question, but anyway, I think I'm not the only one who confused by this. So, in my situation Add is even worse than AddOrUpdate.
The only solution I've come to is following:
public static void AddWhenNew<T>(this DbContext ctx, T item) where T : Entity
{
var old = ctx.Set<T>().Find(item.Id);
if (old == null)
ctx.Set<T>().AddOrUpdate(item);
/* Unfortunately this approach throws exception when I try to set state to Unchanged.
Something like:"The entity already exists in the context"
ctx.Set<T>().AddOrUpdate(item);
if (ctx.Entry(item).State != System.Data.Entity.EntityState.Added)
ctx.Entry(item).State = System.Data.Entity.EntityState.Unchanged;
*/
}
When I submit the form, input error is occur. JourneyDate is instance of 'Date'. But ,here it become String which is not accepted by the setter and getter.
<s:hidden name="JourneyDate" value="%{JourneyDate}"></s:hidden>
I want JourneyPlan as Date Type, but it become String.
Try intercepting the value before passing it to the getter/setter. For example send JourneyDateString from your form, create a Date from the String, and then pass that to your getter/setter. Something like:
public void setJourneyDateString(String journeyDateString)
{
//journeyDateString could be "2013-03-28" for example
Date journeyDate = new SimpleDateFormat("yyyy-MM-dd").parse(journeyDateString);
setJourneyDate(journeyDate);
}
The object that you've set in the value attribute will keep it's type as Date. Then you need to define corresponding setter in the action to set the value of the Date. It will convert to string if you place the value in the body of the tag.
I am using rich faces select component.
I want dynamic values when user manually type some thing in the select component.
<rich:select enableManualInput="true" defaultLabel="start typing for select" value="#{supplierSearchBean.userInput}">
<a4j:ajax event="keyup" execute="#this" listener="#{supplierSearchBean.userInputChange}"/>
<f:selectItems value="#{supplierSearchBean.selectOptions}" />
</rich:select>
Java code as follows
public void userInputChange(ActionEvent ae){
Map map = ae.getComponent().getAttributes();
System.out.println(map.toString());
}
public void setUserInput(String userInput) {
System.out.println("userINput = " + userInput);
this.userInput = userInput;
}
Here i found 2 issues
1st: setUserINput always print empty string when user type value
2nd: listener method never get call.
any help ?
The problem is most probably that there is no selected value while the user types, and this component restricts the allowed values to the specified select items. A partial input is thus not valid and cannot be bound to your bean.
I think you could get the expected behavior if you use a rich:autocomplete instead. However, if you want to restrict the allowed values, maybe you can keep your rich:select and listen for the selectitem event.
Override getItems function in richfaces-utils.js file in richfaces-core-impl-4.0.0.Final.jar under richfaces-core-impl-4.0.0.Final\META-INF\resources folder.
Change the condition of pushing items to be
if(p != -1)
instead of
if(p == 0)
This should fix the issue.
I've a collection of a class' properties and would like to update each one's value by iterating over the collection through the index.
1) I create the collection of properties this way
private PropertyInfo[] GetPropertiesOfMyClass()
{
Type myType = (typeof(myClass));
PropertyInfo[] PropertyInfoArray = myType.GetProperties(
BindingFlags.Public |
BindingFlags.Instance);
return PropertyInfoArray;
}
2)Now, I'd like to set up the value of each one depending on the index this way
public void UpdateProperty(MyClass instanceOfMyClass, string valueToUpdate, int index)
{
//TODO:
//1. Get an individual property from the GetPropertyOfMyClass() using index
//2. Update the value of an individual property of the instanceOfMyClass
}
I'd like to be able to call UpdateProperty from a Controller like this:
UpdateProperty(instanceOfMyClass, valueToUpdate, indexOfTheProperty);
Honestly, I do not know how to involve the instanceOfMyClass in the game as GetProperty only plays with myClass.
Since I saw that I can use Name, PropertyType, ... to get information on the property. So, I've tried also GetPropertyOfMyClass()[index].SetValue(...), but I was lost in the arguments of its constructor, so I abandoned.
What I want is to be able to update the value of a property in my collection just by using the index.
Thanks for helping
Your guess was correct. You use SetValue() to update the value - this is how to do it:
GetPropertyOfMyClass()[index].SetValue( instanceOfMyClass, valueToUpdate, null);
The last argument can be null:
Optional index values for indexed properties. This value should be null for non-indexed properties.