How can I get proper `PropertyName` when I use Javers to diff objects - javers

class Person {
#PropertyName("detail.change")
Detail detail
}
class Detail {
String name;
String age;
}
I have a class named Person.
and it has a field named detail which is also an object
now i want to compare two Person
and no matter what the changes are, i want it returns me "detail.change" as the property name
for now if the name or age is different. javers returns me name or age
do you have any idea that i can do this?
really appreciate your help!

You can do it only if you map Detail to ValueType (https://javers.org/documentation/domain-configuration/#ValueType). ValueType is treated by Javers as atomic value. When Detail is mapped to ValueObject, Javers reports concrete properties of Detail as changed.

Related

Custom serialization of specific return type for DataFetcher

I am using Spring for GraphQL (version 2.7.0-M1).
In my domain model, a lot of properties return an object Foo. This object must be serialized to a String based on data available from GraphQlContext. So the schema looks like:
type Parent {
code: String!
foo: String
...
}
It is easy to do this with #SchemaMapping for a specific parent type.
#SchemaMapping(typeName = "Parent", field = "foo")
public String foo(Parent parent, DataFetchingEnvironment env) {
var context = env.getGraphQlContext();
return ...
However, this is not very DRY. I am looking for a way to have this code at one place, like a custom scalar.
Is there a way to do this with spring-graphql / graphql-java?
Example
An example is a Localized<T> object we use. For instance a Product instance has Localized<String> properties for title and description (and more).
For the GraphQL query we can set the context, part of the context is the Locale. For all Localized property values the value can be converted to the string value for the locale. We are looking for a way to do this automagically. Otherwise it creates a lot of boiler plate code
Would #ContextValue help here? This would remove a bit of boilerplate from your controller handlers.
#SchemaMapping(typeName = "Parent", field = "foo")
public String foo(Parent parent, #ContextValue Foo foo) {
If you'd like something more involved, I think you should elaborate on the exact relationship between an attribute of one or multiple types in your schema, and some random value in the context.
Maybe you could come up with some concrete example here?

Custom Comparators to reflect multiple changes as well as deeper diffs

I am attempting to implement CustomComparators for certain classes. The first question I have is how to return back multiple ValueChanges in my CustomComparator. I seem to only be able to return back a single ValueChange on that object when more than one field might have changed. Additionally, I can't figure out how to get Javers to generate a diff for objects that appear as fields in the class my CustomCommparator is overriding. Example below:
I have the following classes defined below where we have a Person owning a Store that has an Item they sell there.
public class Person
public Store store
public class Store
public String name
public Item item
public String location
public class Item
public String name
Question:
1. How can I implement a CustomComparator for Store such that it creates two ValueChanges: one for name and one for location.
2. How can I use that same CustomComparator to get Javers to also do a diff on item?
Thanks!
Shortly, you can't. The CustomPropertyComparator.compare() method returns PropertyChange which can be complex object (like ListChange) or any kind of object that extends PropertyChange. But still, PropertyChange describes a Change on exactly one Property.
Doing it javers-way means registering CustomValueComparator for each Value Type.
For example, if you have the Item class:
class Item {
Price price
Characteristics Characteristics
}
Register custom comparators for each atomic Value Type:
javersBuilder
.registerValue(Price.class, (a,b) -> a.compareTo(b) == 0)
.registerValue(Characteristics.class, (a,b) -> a.compareTo(b) == 0)

Servicestack Ormlite multi-column constraint fails where constraint includes Enum

I am using ServiceStack.Ormlite, and also make heavy use of the automatic handling of enums whereby they are stored in the db as strings but retrieved and parsed nicely back into Enums on retrieval, so I can do easy type-comparison - say, for a property "UserRole" in the db/table class "User" of enum type "UserRoleEnum" (just for demonstration).
This works great.. until I want to use the enum property to define a multi-column unique constraint
CompositeIndexAttribute(bool unique, params string[] fieldNames);
like:
[CompositeIndex(true, nameof(UserId), nameof(UserRole)]
public class User
{
public long UserId {get;set;}
public UserRoleEnum UserRole {get;set;
}
(as per :
How to Create Unique Constraint with Multiple Columns using ServiceStack.OrmLite? ).
At which time i get:
System.Data.SqlClient.SqlException
Column 'UserRole' in table 'User' is of a type that is invalid for use as a key column in an index.
I currently see options as:
a) Define UserRole as a string (isntead of UserRoleEnum ) in the table entity class and lose the Enum use.... having to manually test the value each time to confirm that the db value is one that i expect in my business logic later
b) Continue to use UserRoleEnum but lose the ability to declare multicolumn uniqueconstraints using the class attribute, and probably have to create these manually using a subsequent db migration script?
Is there any way to make the enums and the multicolumn constraint play nicely, out of the box?
This issue was because enum properties were using the default string definition fallback of VARCHAR(MAX) which SQL Server doesn't let you create indexes on whereas the column definition of a string property is VARCHAR(8000).
This issue is now resolved from this commit which now uses the VARCHAR(255) string definition of the EnumConverter Type Converter. This change is available from v4.5.5 that's now available on MyGet.
Otherwise you can also change the size of the column definition to match a string property by adding a [StringLength] attribute, e.g:
[CompositeIndex(true, nameof(UserId), nameof(UserRole))]
public class User
{
public long UserId { get; set; }
[StringLength(8000)]
public string UserRole { get; set; }
}

DevExpress XtraReport data binding for object attributes

I have an report, in which I like to show reports about some Employees. The Employee Class contains the following attributes :
public class Employee {
public string name;
public Branch branch;
}
I have an list of employees, and I bind them to the report columns. It is showing employee name without any problem in the first column of the report table, but in the second column it is showing the Branch object's assembly, namespace etc etc. (It is obvious, of course, since I am binding the whole Branch object to that column).
My question is : how can I show employee name in one column and corresponding branch name in another column?
My Branch Class has the following definition :
public class Branch{
public int branchId;
public string name;
}
I am adding an data source to the report class from the tool box, creating an XtraReport object, and simply assigning an Employee list as follows :
XtraReport1.DataSource = EmployeeList;
XtraReport objects can do sub-property binding. Give your label the text "[branch.name]" (rather than picking the data source with the designer drop-down).
your binding probably looks like:
....DataBindings.Add(new Binding("Text", employee, "branch"));
change it to
....DataBindings.Add(new Binding("Text", employee.branch, "name"));

linq to sql OnLoaded() with SQL View?

I am trying to extend my Linq-to-Sql entity with a few extra properties. These are "calculated" properties based on data from the underlying SQL View. For example, think of having a Date of Birth field, which is used to calculate an extended Age field.
I tried to extend my entity class by extending the OnLoaded() method.
I get a compile time error however stating that I cannot create it. I checked the designer code for my LTS entity class, and it doesn't have a partial definition for any of the expected extension points.
I checked a few of my other LTS entity classes and they do have these extension points. The only difference I see is that the one without is loaded from a SQL View, rather than a table. Is there a way to hook into a "Loaded" event when loading from a SQL View?
TIA!
I found that I did not have a PrimaryKey specified for my Linq-to-Sql entity class. I believe without a Primary Key specified, no extension methods generated in the entity class. Once I specified a Primary Key on my LTS entity class definition (through the designer), I was able to extend the OnLoaded() event.
You can do this by means of a property. Just create a partial class with the same name as your entity. Any properties or methods that you add will automatically be part of the entity and allow to use any of its members.
Here's an example of the pattern:
public partial class [The Name of the Entity]
{
public int Age
{
get
{
return CalculateAge(this.DateOfBirth);
}
}
}
Here's some logic on how to calculate the Age (Source: Geekpedia)
public static int CalculateAge(DateTime BirthDate)
{
int YearsPassed = DateTime.Now.Year - BirthDate.Year;
// Are we before the birth date this year? If so subtract one year from the mix
if (DateTime.Now.Month < BirthDate.Month ||
(DateTime.Now.Month == BirthDate.Month && DateTime.Now.Day < BirthDate.Day))
{
YearsPassed--;
}
return YearsPassed;
}

Resources