How to save GORM class with composite id made from its own field? - grails-orm

This is my Domain class
class ReturnReason implements Serializable {
Long returnReasonId
Long languageId
String name
int hashCode() {
def builder = new HashCodeBuilder()
builder.append returnReasonId
builder.append languageId
builder.toHashCode()
}
boolean equals(other) {
if (other == null) return false
def builder = new EqualsBuilder()
builder.append returnReasonId, other.returnReasonId
builder.append languageId, other.languageId
builder.isEquals()
}
static mapping = {
id composite: ["returnReasonId", "languageId"]
version false
}
static constraints = {
name maxSize: 128
}
}
This is my controller code to save my domain class.
def save() {
ReturnReason returnReasonInstance = new ReturnReason(params)
returnReasonInstance.languageId = 1
if (!returnReasonInstance.save(flush: true)) {
render(view: "create", model: [returnReasonInstance: returnReasonInstance])
}
redirect(action: "list")
}
While trying to save in my controller than there is a error in returnReasonId ,i.e returnReasonId rejected value null. How to fix it.??

write validate:false in save action
def save() {
ReturnStatus returnStatusInstance = new ReturnStatus(params)
returnStatusInstance.languageId = 1
if (!returnStatusInstance.save(validate: false, flush: true)) {
render(view: "create", model: [returnStatusInstance: returnStatusInstance])
}
redirect(action: "list")
}

Related

Populating Nested List<> in MVC4 C#

I've got a problem populating nested List<>
The object graph looks like this:
Route ⇒ Section ⇒ Co-ordinates
Whenever I try to populate Сoordinates list it just overwrites previous record and at the end gives me only the last Coordinate record. But I want all the Co-ordinates.
Here is my controller code:
List<RequestRouteDataClass> result = new List<RequestRouteDataClass> {
new RequestRouteDataClass() {
RouteRequestId = objRouteManagement.RouteRequestId,
RouteName = objRouteManagement.RouteName,
RouteDescription = objRouteManagement.RouteDescription,
RouteSections = new List<RouteSections> {
new RouteSections() {
Route_Sections_Id = objSections.Route_Sections_Id,
Section_Speed = objSections.Section_Speed,
Section_Description = objSections.Section_Description,
RouteCordinatesSections = new List<SectionCoordinatesRelationData> {
new SectionCoordinatesRelationData() {
SectionCoordinate_Relat_Id = objSectionsCordinates.SectionCoordinate_Relat_Id,
CoordinateLat = objSectionsCordinates.CoordinateLat,
CoordinateLag = objSectionsCordinates.CoordinateLag
}
}
}
}
}
If you want to use Nested List.
Your Model Contains =>
public class MainModelToUse
{
public MainModelToUse()
{
FirstListObject = new List<FirstListClass>();
}
public List<FirstListClass> FirstListObject { get; set; }
}
public class FirstListClass
{
public FirstListClass()
{
SecondListObject = new List<SecondListClass>();
}
public List<SecondListClass> SecondListObject { get; set; }
}
public class SecondListClass
{
public SecondListClass()
{
ThirdListObject = new List<ThirdListClass>();
}
public List<ThirdListClass> ThirdListObject { get; set; }
}
public class ThirdListClass
{
}
Your Code to Nested List =>
FirstListClass vmFirstClassMenu = new FirstListClass();
vmFirstClassMenu.SecondListClass = new List<SecondListClass>();
FirstListClass vmFirstClassCategory = new FirstListClass();
var dataObject1 = //Get Data By Query In Object;
foreach (Model objModel in dataObject1)
{
vmFirstClassCategory = new FirstListClass
{
//Your Items
};
var DataObject2 = //Get Data By Query In Object;
vmFirstClassCategory.SecondListClass = new List<SecondListClass>();
foreach (SecondListClass menuItem in DataObject2)
{
SecondListClass vmFirstClassMenuItem = new SecondListClass
{
//Your Items
};
var DataObject3 = //Get Data By Query In Object;
vmFirstClassMenuItem.ThirdListClass = new List<ThirdListClass>();
foreach (ThirdListClass price in DataObject3)
{
ThirdListClass vmThirdClassobj = new ThirdListClass
{
//Your Items
};
vmFirstClassMenuItem.ThirdListClass.Add(vmThirdClassobj);
}
vmFirstClassCategory.SecondListClass.Add(vmFirstClassMenuItem);
}
}
Hope this is what you are looking for.
First off: spacing helps with readability (edit: but I see you fixed that in your question already):
List<RequestRouteDataClass> result = new List<RequestRouteDataClass>
{
new RequestRouteDataClass()
{
RouteRequestId = objRouteManagement.RouteRequestId,
RouteName = objRouteManagement.RouteName,
RouteDescription = objRouteManagement.RouteDescription,
RouteSections = new List<RouteSections>
{
new RouteSections()
{
Route_Sections_Id = objSections.Route_Sections_Id,
Section_Speed = objSections.Section_Speed,
Section_Description = objSections.Section_Description,
RouteCordinatesSections = new List<SectionCoordinatesRelationData>
{
new SectionCoordinatesRelationData()
{
SectionCoordinate_Relat_Id = objSectionsCordinates.SectionCoordinate_Relat_Id,
CoordinateLat = objSectionsCordinates.CoordinateLat,
CoordinateLag =objSectionsCordinates.CoordinateLag
}
}
}
}
}
};
Next: what you are doing with the above is initiating your lists with a single element in each list. If you want more elements, you have to add them. I recommend using a foreach and the Add() functionality to fill your lists.
From your example it is not clear how your source data is stored, but if you have multiples of something I would expect those too to be in a list or an array of some kind.

Issue with Web Api Custom Model Binder in MVC4

I am using Mvc4 with WebApi.
I am using Dto objects for the webApi.
I am having enum as below.
public enum Status
{
[FlexinumDefault]
Unknown = -1,
Active = 0,
Inactive = 100,
}
Dto structure is as follows.
[DataContract]
public class abc()
{
[DataMemebr]
[Required]
int Id{get;set;}
[DataMember]
[Required]
Status status{get;set}
}
I have created Custom Model Binder which will validate the enum(status) property in the dto object and return false if the enum value is not passed.
if the status enum property is not passed in the dto object,we should throw exception
public bool BindModel(System.Web.Http.Controllers.HttpActionContext actionContext, System.Web.Http.ModelBinding.ModelBindingContext bindingContext)
{
var input = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
if (input != null && !string.IsNullOrEmpty(input.AttemptedValue))
{
if (bindingContext.ModelType == typeof(Enum))
{
//var actualValue = null;
var value = input.RawValue;
in the api controller,i have action method like
public void Create([FromUri(BinderType = typeof(EnumCustomModelBinder))]abcdto abc)
{
In global.asax.cs
i have set like
GlobalConfiguration.Configuration.BindParameter(typeof(Enum), new EnumCustomModelBinder());
the issue i am facing is the custombinder
var input = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
,the input value is coming as null.
Please sugggest
I found the solution
This works fine,but the default implementation of model binder is missing.
public bool BindModel(System.Web.Http.Controllers.HttpActionContext actionContext, ModelBindingContext bindingContext)
{
var json = actionContext.Request.Content.ReadAsStringAsync().Result;
if (!string.IsNullOrEmpty(json))
{
var jsonObject = (JObject) Newtonsoft.Json.JsonConvert.DeserializeObject(json);
var jsonPropertyNames = jsonObject.Properties().Select(p => p.Name).ToList();
var requiredProperties = bindingContext.ModelType.GetProperties().Where(p =>p.GetCustomAttributes(typeof(RequiredAttribute),
false).Any()).ToList();
var missingProperties = requiredProperties.Where(bindingProperty => !jsonPropertyNames.Contains(bindingProperty.Name)).ToList();
if (missingProperties.Count > 0)
{
missingProperties.ForEach(
prop =>
{
if (prop.PropertyType.IsEnum)
actionContext.ModelState.AddModelError(prop.Name, prop.Name + " is Required");
});
}
var nullProperties = requiredProperties.Except(missingProperties).ToList();
if (nullProperties.Count > 0)
{
nullProperties.ForEach(p =>
{
var jsonvalue = JObject.Parse(json);
var value = (JValue)jsonvalue[p.Name];
if (value.Value == null)
{
actionContext.ModelState.AddModelError(p.Name, p.Name + " is Required");
}
});
}
}
// Now we can try to eval the object's properties using reflection.
return true;
}

how to access session in integration test in grails?

In my project, i set session.loggedInUser in login controller. But during integration test , we dont use login controller. So i have set value for session.loggedInUser. But i couldn't use session in that place. How can i use session in integration Test. Give some solution for this. thank you in advance
class MaritalStatusIntegrationTests {
#Test
void testCategoryAudit() {
RequestContextHolder.currentRequestAttributes().session.loggedInUser="Anantha"
def category = new Category(name:"Single")
category.save(flush:true)
assert CategoryAudit.count() == 1
category.name="Married"
category.save(flush:true)
assert CategoryAudit.count() == 2
}
}
Category.groovy:
class Category {
static constraints = {
name blank:false
}
String name
//Auditing
static auditable = false
def onSave = {
new CategoryAudit(this,'Insert').save(failOnError:true)
}
}
CategoryAudit.groovy:
import org.springframework.web.context.request.RequestContextHolder
class CategoryAudit {
String name
String operation
String doneBy
Date txnDate
def CategoryAudit(){}
def CategoryAudit(Category category , String operation) {
this.name = category.name
this.operation = operation
this.doneBy = RequestContextHolder.currentRequestAttributes().session.loggedInUser
this.txnDate = new Date()
}
}
No such property: RequestContextHolder for class:
com.vasco.gs.MaritalStatusIntegrationTest.
Just to clean up, according to the OP, it was missing the import for RequestContextHolder.

Insert in nested field

I'm a new user in LINQ to SQL and I have some problems using it.
I've used LINQ to SQL Designer and I have created my classes, mapped on the DB tables.
In particular, I have one class, named voice:
[global::System.Data.Linq.Mapping.TableAttribute(Name="dbo.voce")]
public partial class voce : INotifyPropertyChanging, INotifyPropertyChanged
{
private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(String.Empty);
private int _id_voce;
... other private fields;
private int _category;
private EntityRef<category> _category1;
public voce()
{
this._riepilogo = new EntitySet<riepilogo>(new Action<riepilogo>(this.attach_riepilogo), new Action<riepilogo>(this.detach_riepilogo));
this._hera = default(EntityRef<hera>);
this._category1 = default(EntityRef<category>);
OnCreated();
}
[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_id_voce", AutoSync=AutoSync.OnInsert, DbType="Int NOT NULL IDENTITY", IsPrimaryKey=true, IsDbGenerated=true)]
public int id_voce
{
get
{
return this._id_voce;
}
set
{
if ((this._id_voce != value))
{
this.Onid_voceChanging(value);
this.SendPropertyChanging();
this._id_voce = value;
this.SendPropertyChanged("id_voce");
this.Onid_voceChanged();
}
}
}
......
[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_category", DbType="Int NOT NULL")]
public int category
{
get
{
return this._category;
}
set
{
if ((this._category != value))
{
if (this._category1.HasLoadedOrAssignedValue)
{
throw new System.Data.Linq.ForeignKeyReferenceAlreadyHasValueException();
}
this.OncategoryChanging(value);
this.SendPropertyChanging();
this._category = value;
this.SendPropertyChanged("category");
this.OncategoryChanged();
}
}
}
As you can see, voce class has a field named category that refers to a table named category.
When I add a new voce to my database, I create a new voce istance and, using the DataContext, i simply add it, using:
voce v = new voce(){...field, category1 = //create or retrieve category};
In particular, the category field is retrieved from the DB if already exists or, if not, it is inserted, before I insert the voice.
The problem is that when I add the voice in the database:
datacontext.InsertOnSubmit(v);
datacontext.SubmitChanges();
it inserts the category again, failing with the unique contraint.
How can I add a voice without adding every nested object?
Thank you and sorry for my bad English.
internal category GetCategoryFromDescription (string desc, Utility.VOICE_MODALITY mode)
{
bool type = mode == Utility.VOICE_MODALITY.ENTRATA ? true : false;
var query = from cat in dc.category
where cat.description == desc && cat.type == type
select cat;
if (query.Count() == 0)
{
category newC = new category() { description = desc };
dc.category.InsertOnSubmit(newC);
dc.SubmitChanges();
return newC;
}
else
return query.Single();
}

How to build object hierarchy from SQL query? (for WPF TreeView)

thanks for taking the time out to read this post.
I'm having trouble trying to build a hierarchial object when getting data from my SQL database.
Please note that I am a little bit of a newbie programmer.
How do you build a hierarchial object that has unknown levels? When I say unknown levels I mean, each node may have varying numbers of child nodes, which in turn may have varying numbers of its own child nodes, so on and so on.
The idea is that I need to create a hierarchial object using my SQL data to bind to WPF TreeView control.
Below I have included the code I have so far.
The first bit of code is my Class made up of Properties. Note that the "Products" class has an ObservableCollection referencing itself. I think this is how you construct the nested nodes. i.e. a list inside a list.
The second piece of code is my Get Method to download the data from the SQL database. Here is where I need to some how sort the downloaded data into a hierarchy.
Products Class (properties)
public class Products : INotifyPropertyChanged, IDataErrorInfo
{
private Int64 m_ID;
private SqlHierarchyId m_Hierarchy;
private string m_Name;
private ObservableCollection<Products> m_ChildProducts;
// Default Constructor
public Products()
{
ChildProducts = new ObservableCollection<Products>();
}
//Properties
public Int64 ID
{
get
{
return m_ID;
}
set
{
m_ID = value;
OnPropertyChanged(new PropertyChangedEventArgs("ID"));
}
}
public SqlHierarchyId Hierarchy
{
get
{
return m_Hierarchy;
}
set
{
m_Hierarchy = value;
OnPropertyChanged(new PropertyChangedEventArgs("Hierarchy"));
}
}
public String Name
{
get
{
return m_Name;
}
set
{
m_Name = value;
OnPropertyChanged(new PropertyChangedEventArgs("Name"));
}
}
public Int16 Level
{
get
{
return m_Level;
}
set
{
m_Level = value;
OnPropertyChanged(new PropertyChangedEventArgs("Level"));
}
}
public Int64 ParentID
{
get
{
return m_ParentID;
}
set
{
m_ParentID = value;
OnPropertyChanged(new PropertyChangedEventArgs("ParentID"));
}
}
public ObservableCollection<Products> ChildProducts
{
get
{
return m_ChildProducts;
}
set
{
m_ChildProducts = value;
OnPropertyChanged(new PropertyChangedEventArgs("ChildProducts"));
}
}
//INotifyPropertyChanged Event
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (PropertyChanged != null)
PropertyChanged(this, e);
}
}
Method which gets data from SQL DB:
public static ObservableCollection<Products> GetProductsHierarchy()
{
ObservableCollection<Products> productsHierarchy = new ObservableCollection<Products>();
SqlConnection connection = new SqlConnection(DBConnection.GetConnection().ConnectionString);
string selectStatement = "SELECT ID, Hierarchy, Name, Hierarchy.GetLevel() AS Level, Hierarchy.GetAncestor(1) AS ParentHierarchy, " +
"(SELECT ID " +
"FROM SpecProducts " +
"WHERE (Hierarchy = SpecProducts_1.Hierarchy.GetAncestor(1))) AS ParentID " +
"FROM SpecProducts AS SpecProducts_1 " +
"WHERE (EnableDisable IS NULL) " +
"ORDER BY Hierarchy";
SqlCommand selectCommand = new SqlCommand(selectStatement, connection);
try
{
connection.Open();
SqlDataReader reader = selectCommand.ExecuteReader();
while (reader.Read())
{
Products product = new Products();
product.ID = (Int64)reader["ID"];
product.Name = reader["Name"].ToString();
product.Hierarchy = (SqlHierarchyId)reader["Hierarchy"];
product.Level = (Int16)reader["Level"];
if (reader["ParentID"] != DBNull.Value)
{
product.ParentID = (Int64)reader["ParentID"];
}
else
{
product.ParentID = 0;
}
productsHierarchy.Add(product);
// *** HOW TO BUILD HIERARCHY OBJECT WITH UNKNOWN & VARYING LEVELS?
// *** ADD PRODUCT TO CHILDPRODUCT
}
return productsHierarchy;
}
catch (SqlException ex)
{
throw ex;
}
finally
{
connection.Close();
}
}
Below I have attached an image showing the structure of my SQL Query Data.
Please note that the hierarchy level may go deeper when more products are added in the future. The Hierarchy object I need to create should be flexible enough to expand no matter what the number of node levels are.
Thank you very much for your time, all help is greatly appreciated.
********* EDIT 26/04/2012 14:37 *******************
Please find below a link to download my project code (this only contains treeview code).
Can someone please take a look at it to see why I cannot create nodes beyond 2 levels?
The code was given to me by user HB MAAM. Thank you "HB MAAM" for your help so far!
Click this link to download code
I will create an example for you,
1- first i will create a class that holds the data that comes from the DB
public class SqlDataDto
{
public int? Id { get; set; }
public int? ParentId { get; set; }
public String Name { get; set; }
public String OtherDataRelatedToTheNode { get; set; }
}
2- that data will be converted to hierarchal data and we will use this class to hold it:
public class LocalData : INotifyPropertyChanged
{
private int? _id;
public int? Id
{
get { return _id; }
set { _id = value; OnPropertyChanged("Id"); }
}
private int? _parentId;
public int? ParentId
{
get { return _parentId; }
set { _parentId = value; OnPropertyChanged("ParentId"); }
}
private string _name;
public String Name
{
get { return _name; }
set { _name = value; OnPropertyChanged("Name"); }
}
private string _otherDataRelatedToTheNode;
public String OtherDataRelatedToTheNode
{
get { return _otherDataRelatedToTheNode; }
set { _otherDataRelatedToTheNode = value; OnPropertyChanged("OtherDataRelatedToTheNode"); }
}
private LocalData _parent;
public LocalData Parent
{
get { return _parent; }
set { _parent = value; OnPropertyChanged("Parent"); }
}
private ObservableCollection<LocalData> _children;
public ObservableCollection<LocalData> Children
{
get { return _children; }
set { _children = value; OnPropertyChanged("Children"); }
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(String propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this,new PropertyChangedEventArgs(propertyName));
}
}
}
3- finally we need to change the sql data to hierarchical one:
public List<LocalData> GetHerachy(List<SqlDataDto> sqlData)
{
var sqlParents = sqlData.Where(q => q.ParentId == null).ToList();
var parents = sqlParents.Select(q => new LocalData {Id = q.Id, Name = q.Name}).ToList();
foreach (var parent in parents)
{
var childs = sqlData.Where(q => q.ParentId == parent.Id).Select(q => new LocalData { Id = q.Id, Name = q.Name , Parent = parent});
parent.Children = new ObservableCollection<LocalData>(childs);
}
return parents;
}
4- then you can create a dummy data and convert it and show it in the tree:
var sqlData = new List<SqlDataDto>
{
new SqlDataDto {Id = 1, ParentId = null, Name = "F1"}
, new SqlDataDto {Id = 2, ParentId = null, Name = "F2"}
, new SqlDataDto {Id = 3, ParentId = 1, Name = "S1"}
, new SqlDataDto {Id = 4, ParentId = 2, Name = "S21"}
, new SqlDataDto {Id = 5, ParentId = 2, Name = "S22"}
};
treeView.ItemsSource = GetHerachy(sqlData);
5- the tree should be like:
<TreeView Name="treeView">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children}">
<TextBlock Text="{Binding Name}" />
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
You need to use recursion to fill the Child-List of every object. This is necessary for the WPF HierarchicalDataTemplate to work. Otherwise you only get the first level.
There is an alternative using the Linq method ForEach() and passing an Action Argument. The following solution is very straight forward and easy to understand:
public List<Product> Products { get; set; }
public MainViewModel()
{
Products = new List<Product>();
Products.Add(new Product() { Id = 1, Name = "Main Product 1", ParentId = 0 });
Products.Add(new Product() { Id = 3, Name = "Sub Product 1", ParentId = 1 });
Products.Add(new Product() { Id = 4, Name = "Sub Product 2", ParentId = 1 });
Products.Add(new Product() { Id = 5, Name = "Sub Product 3", ParentId = 1 });
Products.Add(new Product() { Id = 6, Name = "Sub Product 3.1", ParentId = 5 });
this.ProcessRootNodes();
}
private void ProcessRootNodes()
{
var rootNodes = Products.Where(x => x.ParentId == 0).ToList();
for (int i = 0; i < rootNodes.Count; i++)
{
rootNodes[i].Children = this.AddChildren(rootNodes[i]);
}
}
private List<Product> AddChildren(Product entry)
{
var children = Products.Where(x => x.ParentId == entry.Id).ToList();
for(int i=0;i<children.Count;i++)
{
children[i].Children = this.AddChildren(children[i]);
}
return children;
}
// *** HOW TO BUILD HIERARCHY OBJECT WITH UNKNOWN & VARYING LEVELS?
Instead of
ObservableCollection<Products> productsHierarchy = new ObservableCollection<Products>();
use Dictionary<Int64, Products> IdToProduct = new ...
As you loop your products; do a IdToProduct[product.ID] = product;
Then, loop the completed IdToProduct collection and do;
if(product.ParentID != 0)
{
IdToProduct[product.ParentID].ChildProducts.Add(product);
}
Now, your Product --> ChildProducts relation is mapped out.
Optionally, add properties to the Products class:
public bool IsCategory { get { return (ChildProducts.Count >= 1); } } // e.g. Oven
public bool IsProduct { get { return !(IsCategory); } } // e.g. Electric (Oven)
Now, you have most of the model for your view defined.
This article is the de facto starting point for using the WPF TreeView.
Hint: a starting point for your HierarchicalDataTemplate
<TreeView.ItemTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:Products}"
ItemsSource="{Binding ChildProducts}">
<TextBlock Text="{Binding Name}" />
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
You should create a MainViewModel class which has:
public Products RootProduct { get; set; } (notify property changed property)
after you do your SQL parsing and what not; do:
RootProduct = IdToProduct.FirstOrDefault(product => (product.Level == 0));
<TreeView ItemsSource="{Binding RootProduct.ChildProducts}">