Getting Parent Name null in child class audit log in Grail - grails

I have Parent and Child class which has one to many mapping and I want to log Save action on both classes but at the time of saving log parent object is null in child class but it works fine for Parent class log
Here is my AuditLog, Parent and Child class
class AuditLog{
String objectNameType = null;
def onSave = { newMap ->
String objectName = newMap[objectNameType]; // here I am getting null for child class save
//code for storing logs
}
}
class Parent extends AuditLog{
String name;
List child = new ArrayList()
static hasMany = [ child:Child ]
String objectNameType = name;
public String toString(){
return name;
}
}
class child extends AuditLog{
String childName;
static belongsTo =[ parent : Parent];
String objectNameType = parent;
public String toString(){
return childName;
}
}
I am using Grails 1.3.7 version and audit-logging 0.5.5
Any lead will be appreciated.
Thanks in advance

In Controller when I tried to access child.parent I am getting it as null. So I set it manually by iterating over child and it resolves my issue.

Related

How to apply a JsonView to a nested entity

I have the following JsonViews defined:
public class EntityJsonView {
public static class Detailed extends Abbreviated {
}
public static class AuditedDetailed extends Detailed {
}
public static class Abbreviated {
}
}
Then I have these classes:
public Class Customer {
#JsonView(EntityJsonView.Abbreviated.class)
private Integer id;
#JsonView(EntityJsonView.Abbreviated.class)
private String name;
#JsonView(EntityJsonView.Detailed.class)
private String phone;
#JsonView(EntityJsonView.Detailed.class)
private List<Invoice> invoices;
}
public Class Invoice {
#JsonView(EntityJsonView.Abbreviated.class)
private Integer id;
#JsonView(EntityJsonView.Detailed.class)
private Customer customer;
#JsonView(EntityJsonView.Detailed.class)
private Employee salesman;
#JsonView(EntityJsonView.Abbreviated.class)
private Date invoiceDate;
#JsonView(EntityJsonView.Abbreviated.class)
private Double amount;
}
I return my customer list like this:
#JsonView(EntityJsonView.Detailed.class)
public ResponseEntity<List<Customer>> getCustomerList() {
List<Customer> custs = customerService.getAll();
return new ResponseEntity<List<Customer>>(custs , HttpStatus.OK);
}
While I want the Customer instances to be serialized using the Detailed view, I want the nested Invoice instances to be serialized using the Abbreviated view. By the same token, when I serialize a list of Invoices using the Detailed view, I want the nested Customer instances to be serialized using the Abbreviated view. This is not just a problem of recursion because there are lots of other attributes I want to remove as well.
I've searched high and low for a solution but perhaps I'm not using the right keywords.
My predecessor in this job accomplished this using #JsonIgnoreProperties but that is proving to be a maintenance problem. When a new attribute is added to a class, I have to hunt down all the ignore lists and decide if it needs to be ignored or not. It would be easier if there was a corresponding #JsonIncludeProperties.
Has anyone found a better way to accomplish this?
I figured out a way to sort of do this and it works for my environment. I'm posting in case someone else has a similar issue. The first step is to create a view for each of your top-level entities. In this example, those will be Foo, Bar, and Snafu. These should all inherit from an abbreviated view.
public class EntityViews {
public static interface Abbr {}
public static interface Foo extends Abbr {}
public static interface Bar extends Abbr {}
public static interface Snafu extends Abbr {}
public static interface Detailed extends Foo, Bar, Snafu {}
}
I used interface because it allows multiple inheritance. All the main class views end up in the Detailed view. Now for the classes:
#JsonView(EntityViews.Foo.class)
public class Foo {
#JsonView(EntityViews.Abbr.Class)
private Integer id;
#JsonView(EntityViews.Abbr.Class)
private String name;
private String description;
private Bar bar;
}
#JsonView(EntityViews.Bar.class)
public class Bar {
#JsonView(EntityViews.Abbr.Class)
private Integer id;
#JsonView(EntityViews.Abbr.Class)
private String name;
private List<Snafu> snafus;
}
#JsonView(EntityViews.Snafu.class)
public class Snafu {
#JsonView(EntityViews.Abbr.Class)
private Integer id;
#JsonView(EntityViews.Abbr.Class)
private String name;
#JsonView(EntityViews.Bar.class, EntityViews.Snafu.class)
#JsonIgnoreProperties("parent", "children")
private Snafu parent;
#JsonIgnoreProperties("parent", "children")
private List<Snafu> children;
}
Now, let's do the endpoints:
#RestController
#RequestMapping("/api/foos")
#CrossOrigin
public class FooController {
#JsonView(EntityViews.Foo.class)
#GetMapping("/")
public ResponseEntity<List<Foo>> get() {
List<Foo> list = service.getAll();
return new ResponseEntity<List<Foo>>(list, HttpStatus.OK);
}
}
#RestController
#RequestMapping("/api/bars")
#CrossOrigin
public class BarController {
#JsonView(EntityViews.Bar.class)
#GetMapping("/")
public ResponseEntity<List<Foo>> get() {
List<Bar> list = service.getAll();
return new ResponseEntity<List<Bar>>(list, HttpStatus.OK);
}
}
#RestController
#RequestMapping("/api/snafus")
#CrossOrigin
public class SnafuController {
#JsonView(EntityViews.Snafu.class)
#GetMapping("/")
public ResponseEntity<List<Snafu>> get() {
List<Snafu> list = service.getAll();
return new ResponseEntity<List<Snafu>>(list, HttpStatus.OK);
}
}
So as we see, each controller assigns the view corresponding to the entity that is being returned. Since those views all
inherit from Abbr, all other entities being returned will have the Abbr view applied to them.
Notice in the Snafu class that the parent attribute is assigned to both the Bar and Snafu views. So when you return a Bar endpoint,
you will get that attribute as well as the Abbr attributes (I haven't tested this so YMMV. Will edit if it doesn't work like I think it will).
The one place this strategy breaks down is if you have attributes that are the same class as the entity. In that case, you will still
have to use #JsonIgnoreProperties to control what is returned but that is a small price to pay for not having to have those on virtually
every entity attribute.

Passing the dbcontext to the repository: A field initializer cannot reference the nonstatic field, method, or property

I have the following controller, in which I create an instance of the BadgeAssignmentRepository. I tried to pass the my dbcontext variable in the declaration of the repository. However I receive A field initializer cannot reference the nonstatic field, method, or property EntryController.db
I have no idea why my code is wrong. Can someone help me?
Here is the controller:
public class EntryController : Controller
{
public EchoLuMvcDbContext db = new EchoLuMvcDbContext();
private BadgeAssignmentRepository baRepository= new BadgeAssignmentRepository(db);
//this db is causing the trouble
Here is the repository:
public class BadgeAssignmentRepository
{
public EchoLuMvcDbContext db { get; set; }
public BadgeAssignmentRepository(EchoLuMvcDbContext context)
{
this.db = context;
}
As the error says, you can't access another field from a field initializer. If your BadgeAssignmentRepository needs a reference to your db field, initialize it in your controller's constructor like this:
public class EntryController : Controller
{
public EchoLuMvcDbContext db = new EchoLuMvcDbContext();
private BadgeAssignmentRepository baRepository;
public EntryController() {
baRepository = new BadgeAssignmentRepository(db);
}
}

Asp.Net WebApi get result

I have the following controller in an ASP.Net WebApi project.
The model is generated with Entity Framework.
public class CategoriesController : ApiController
{
private eLearningDbEntities context = new eLearningDbEntities();
// GET api/Categories
public IEnumerable<Categories> GetCategories()
{
var query = from c in context.Categories
select c;
return query;
}
}
When call the controller from the browser I get the following result, but I want to get only the properties of the Model, not all the context properties. Any ideas what is wrong?
<ArrayOfCategories xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/eLearning.DomainModel">
<Categories xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/" z:Id="i1">
<EntityKey xmlns:d3p1="http://schemas.datacontract.org/2004/07/System.Data" xmlns="http://schemas.datacontract.org/2004/07/System.Data.Objects.DataClasses" z:Id="i2">
<d3p1:EntityContainerName>eLearningDbEntities</d3p1:EntityContainerName>
<d3p1:EntityKeyValues>
<d3p1:EntityKeyMember>
<d3p1:Key>ID</d3p1:Key>
<d3p1:Value xmlns:d6p1="http://www.w3.org/2001/XMLSchema" i:type="d6p1:int">1</d3p1:Value>
</d3p1:EntityKeyMember>
</d3p1:EntityKeyValues>
<d3p1:EntitySetName>Categories</d3p1:EntitySetName>
</EntityKey>
<ID>1</ID>
<Name>e-Business</Name>
</Categories>
<Categories xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/" z:Id="i3">
<EntityKey xmlns:d3p1="http://schemas.datacontract.org/2004/07/System.Data" xmlns="http://schemas.datacontract.org/2004/07/System.Data.Objects.DataClasses" z:Id="i4">
<d3p1:EntityContainerName>eLearningDbEntities</d3p1:EntityContainerName>
<d3p1:EntityKeyValues>
<d3p1:EntityKeyMember>
<d3p1:Key>ID</d3p1:Key>
<d3p1:Value xmlns:d6p1="http://www.w3.org/2001/XMLSchema" i:type="d6p1:int">2</d3p1:Value>
</d3p1:EntityKeyMember>
</d3p1:EntityKeyValues>
<d3p1:EntitySetName>Categories</d3p1:EntitySetName>
</EntityKey>
<ID>2</ID>
<Name>SADE</Name>
</Categories>
</ArrayOfCategories>
Thank you!
You shouldn't be passing back your database entity directly, but instead creating a view model that you can pass back that isolates the message to only the fields that you care about receiving on the client end. e.g.
// Create a View Model to hold appropriate properties
public class MyViewModel
{
public string PropertyA {get; set;}
public string PropertyB {get; set;}
}
...
// Map your entity to the View Model and return it.
var viewModel = context.Categories.Select(
e=>new MyViewModel(){
PropertyA = e.SomeProperty,
PropertyB = e.AnotherProperty
});
return viewModel;

XSD2Code, Is it possible to serialize inherited properties from a parent abstract class?

I have a XSD2Code generated Class and all is working. However I want to generate and store IDs as GUIDs on all Complex class types ie Order, OrderItem etc. to facilitate CRUD from the object Hierarchy. So instead of adding an ID element to every "Record" style dataset in the XML Schema I have created a parent abstract Class from which my XSD2Code classes inherits from. My code can see the ID, and it generates the ID, however it seems that XSD2Code does not see ID and thus ID does not get Serialized.
My Parent Class code:
namespace OrderSystem
{
public abstract class Master
{
private string IdField;
[System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified, Order = 999)]
public String ID
{
get
{
if (IdField == null)
{
IdField = Guid.NewGuid().ToString();
}
return IdField;
}
}
}
}
Which is used by my XSD generated code:
public partial class Product : Master
{
My instinct is that ID is not being serialized, because it is not in the generated class ie "Product" which is a little odd since the rest of the code can see it because it is inherited.
Any thoughts please?
EDIT:
public class Master
{
private string IdField;
[System.Xml.Serialization.XmlAttributeAttribute()]
public String ID
{
get
{
//if (IdField == null)
//{
// IdField = Guid.NewGuid().ToString();
//}
return IdField;
}
set
{
if (value == null)
{
IdField = Guid.NewGuid().ToString();
}
else
{
IdField = value;
}
}
}
}
I sorted this myself. Proved to be an error in the code. Also I removed the "Abstract", not sure if this is necessary. See EDIT above.

Why is my full view model not being serialized by ApiController?

I have the following type hierarchy for ClientIndexModel:
public class ViewModel
{
public virtual IDictionary<string, SelectList> SelectListDictionary
{
get
{
var props = GetType().GetProperties().Where(p => p.PropertyType == typeof(SelectList));
return props.ToDictionary(prop => prop.Name, prop => (SelectList)prop.GetValue(this, null));
}
}
}
public class IndexModel<TIndexItem, TEntity> : ViewModel where TIndexItem : ViewModel where TEntity : new()
{
public List<TIndexItem> Items { get; private set; }
}
public class ClientIndexModel: IndexModel<ClientIndexItem, Client>
{
}
I instantiate in and return a ClientIndexModel from an ApiController as follows:
public ClientIndexModel Get()
{
var model = new ClientIndexModel();
return model;
}
If I inspect model with a breakpoint on the return model; line, the Items property is present, with a count of 0. Yet the JSON returned from this action only has the SelectListDictionary property and no Items property. Why could this be?
Your Items property has a private setter. Properties with private setters are intentionally omitted from serialization as it makes no sense to serialize them because they can never be deserialized back as their values cannot be modified from the outside. So you should either completely remove the setter (as you have done for the SelectListDictionary property), make it public or write a custom formatter using some custom serializer that is capable of serializing properties with private setters.

Resources