Hibernate Envers Audit Query- retrieve only the most recent revision for all entities - hibernate-envers

I would like to retrieve the all recent versions of all entities( i.e. everything in Database) that has changed recently.
Following query fetch revisions of specific entity "MyEntity"
queryObject = auditReader.createQuery().forRevisionsOfEntity(MyEntity.class, false, true).addOrder(AuditEntity.revisionNumber().desc())
But I need a mechanism to fetch records for all entities irrespective of particular entity type.

Look into org.hibernate.envers.track_entities_changed_in_revision.
This setting causes a join-table to be created against the revision-entity where a string-based set of entity names will be tracked for each revision number. With this information, you should be able to build necessary queries using the AuditReader#createQuery() API to iterate all the changes.
In pseudo code, it would be something like:
List<Number> revisions = // create AuditQuery to get all revision numbers
for ( Number revision : revisions ) {
DefaultTrackingModifiedEntitiesRevisionEntity revisionEntity = // create query to get revision entity
for ( String entityName : revisionEntity.getModifiedEntityNames() ) {
// create query based on entityName + revisionNumber
}
}

Related

Hibernate Search add only DocumentId from IndexedEmbedded class

I've an Entity "Invoice" and this one has a many-to-one relationship to Customer-Entity. This Customer-Entity is also used from other Entities for Hibernate Search and so there are many Hibernate Search annotations. For Invoice HS-Index I just want to have the Customer.id in the Invoice index and no other property of Customer.
How is this possible, because in the documentation I've found nothing specific about it.
In recent versions of Hibernate Search, you would simply use #IndexedEmbedded(includePaths = "id").
Hibernate Search 3.4 is very old, though (9 years old), and is missing many features. I'd recommend you upgrade since you're very likely to hit bugs that will never be solved in this version.
If you really have to stick with 3.4, I believe your only solution will be writing a custom bridge:
public class CustomerIdBridge implements StringBridge {
public String objectToString(Object object) {
Customer customer = (Customer) object;
if ( customer == null ) {
return null;
}
Object id = customer.getId();
return id == null ? null : id.toString();
}
}
Then apply the bridge like this:
#ManyToOne(...)
#Field(bridge = #FieldBridge(impl = CustomerIdBridge.class))
private Customer customer;
The resulting field will simply be named "customer" (same name as your property).
See here for more information about bridges in Hibernate Search 3.4.2.

Not able to use IN query in LINQ with Entity Framework

I am using EF Framework to retrieve the data from SQL DB.
Sub Request Table looks like below:
In this table "org_assigneddept" is foreign key to another Department Table.
I have list of Departments as Input and I want to retrieve only those rows from DB whose org_assigneddept is matching the list.
Please find my whole code:-
private List<EventRequestDetailsViewModel> GetSummaryAssignedDeptEventRequests(List<EmpRoleDeptViewModel> vmDept)
{
List<EventRequestDetailsViewModel> vmEventRequestDeptSummary = new List<EventRequestDetailsViewModel>();
RequestBLL getRequestBLL = new RequestBLL();
Guid subRequestStatusId = getRequestBLL.GetRequestStatusId("Open");
using (var ctxGetEventRequestSumm = new STREAM_EMPLOYEEDBEntities())
{
vmEventRequestDeptSummary = (from ers in ctxGetEventRequestSumm.SubRequests
where vmDept.Any(dep=>dep.DeptId == ers.org_assigneddept)
select new EventRequestDetailsViewModel
{
SubRequestId = ers.org_subreqid
}).ToList();
}
}
It is giving the following error at the LINQ Query level:-
System.NotSupportedException: 'Unable to create a constant value of
type 'Application.Business.DLL.EmpRoleDeptViewModel'. Only primitive
types or enumeration types are supported in this context.'
Please let me know as how can I achieve the result
You cannot pass the department VMs to SQL, it doesn't know what those are.
// Extract the IDs from the view models.. Now a list of primitive types..
var departmentIds = vmDept.Select(x => x.DeptId).ToList();
then in your select statement...
..
where departmentIds.Contains(id=> id == ers.org_assigneddept)
..

Hibernate Envers-Get all entities, revision numbers, revision dates and revision types of an Entity by its ID

Using Hibernate Envers I want to get all entities, revision numbers, revision dates and revision types of an Entity by its ID.
Currently I am doing this to obtain the entity, revision number and revision date:
public List<Alumno> obtenerAuditoriaAlumno(Long idAlumno) {
AuditReader auditReader = AuditReaderFactory.get(entityManager);
List<Number> revisionNumbers = auditReader.getRevisions(Alumno.class, idAlumno);
List<Alumno> auditoriaAlumno = new ArrayList<Alumno>();
for (Number rev : revisionNumbers) {
Alumno alumno = auditReader.find(Alumno.class, idAlumno, rev);
Date revisionDate = auditReader.getRevisionDate(rev);
alumno.setRevisionNumber(rev.intValue());
//alumno.setRevisionType(revisionType); // GET THIS
alumno.setRevisionDate(revisionDate);
auditoriaAlumno.add(alumno);
}
return auditoriaAlumno;
}
Is it possible to obtain it with one query?
Should I add these fields directly to the Entity?
I would suggest you take a look at using forRevisionsOfEntity. You access this method by using the AuditReader interface as follows:
auditReader.createQuery().forRevisionsOfEntity(
YourAuditEntityClass.class,
false, // false returns an array of entity and audit data
true // selects the deleted audit rows
);
The important method argument here is the second argument as that influences the returned Object type. When its true, you'll be returned the actual audited entity instances for each revision; however, when its false you'll be returned an Object[] array of values of which are:
The entity instance.
The revision entity instance (where you can get the revision number and date)
The revision type, e.g. ADD, MOD, DEL.
HTH.

How to filter records using group functionality in BreezeJs

I'm developing a client app that uses breezejs and Entity Framework 6 on the back end. I've got a statement like this:
var country = 'Mexico';
var customers = EntityQuery.from('customers')
.where('country', '==', country)
.expand('order')
I want to use There may be hundreds of orders that each customer has made. For the purposes of performance, I only want to retrieve the latest order for each customer. This will be based on the created date for the order. In SQL, I could write something like this:
SELECT c.customerId, companyName, ContactName, City, Country, max(o.OrderDate) as LatestOrder FROM Customers c
inner join Orders o on c.CustomerID = o.CustomerID
group by c.customerId, companyName, ContactName, City, Country
If this was run against the northwind database, only the most recent order row is returned for each customer.
How can I write a similar query in breeze, so that it runs on the server side and therefore returns less data to the client. I know I could handle this all on the client but writing some javascript in a querysucceeded method that could be run by the client - but that's not the goal here.
thanks
For a case like this, you should create a special endpoint method that will perform your query.
Then you can use an Entity Framework query to do what you want, using the LINQ syntax.
Here are two Web API examples:
[HttpGet]
public IQueryable<Object> CustomersLatestOrderEntities()
{
// IQueryable<Object> containing Customer and Order entity
var entities = ContextProvider.Context.Customers.Select(c => new { Customer = c, LatestOrder = c.Orders.OrderByDescending(o => o.OrderDate).FirstOrDefault() });
return entities;
}
[HttpGet]
public IQueryable<Object> CustomersLatestOrderProjections()
{
// IQueryable<Object> containing Customer and Order entity
var entities = ContextProvider.Context.Customers.Select(c => new { Customer = c, LatestOrder = c.Orders.OrderByDescending(o => o.OrderDate).FirstOrDefault() });
// IQueryable<Object> containing just data fields, no entities
var projections = entities.Select(e => new { e.Customer.CustomerID, e.Customer.ContactName, e.LatestOrder.OrderDate });
return projections;
}
Note that you have a choice here. You can return actual entities, or you can return just some data fields. Which is right for you depends upon how you are going to use them on the client. If they are just for display in a
non-editable list, you can just return the plain data (CustomersLatestOrderProjections above). If they can potentially
be edited, then return the object containing the entities (CustomersLatestOrderEntities). Breeze will merge the entities
into its cache, even though they are contained inside this anonymous object.
Either way, because it returns IQueryable, you can use the Breeze filtering syntax from the client to further qualify the query.
var projectionQuery = breeze.EntityQuery.from("CustomersLatestOrderProjections")
.skip(20)
.take(10);
var entityQuery = breeze.EntityQuery.from("CustomersLatestOrderEntities")
.where('customer.countryName', 'startsWith', 'C');
.take(10);

OrientDB - How do I insert a document with connections to multiple other documents?

Using OrientDB 1.7-rc and Scala, I would like to insert a document (ODocument), into a document (not graph) database, with connections to other documents. How should I do this?
I've tried the following, but it seems to insert an embedded list of documents into the Package document, rather than connect the package to a set of Version documents (which is what I want):
val doc = new ODocument("Package")
.field("id", "MyPackage")
.field("versions", List(new ODocument("Version").field("id", "MyVersion")))
EDIT:
I've tried inserting a Package with connections to Versions through SQL, and that seems to produce the desired result:
insert into Package(id, versions) values ('MyPackage', [#10:3, #10:4] )
However, I need to be able to do this from Scala, which has yet to produce the correct results when loading the ODocument back. How can I do it (from Scala)?
You need to create the individual documents first and then inter-link them using below SQL commands.
Some examples given in OrientDB documentation
insert into Profile (name, friends) values ('Luca', [#10:3, #10:4] )
OR
insert into Profile SET name = 'Luca', friends = [#10:3, #10:4]
Check here for more details.
I tried posting in comments above, but somehow the code is not readable, so posting the response separately again.
Here is an example of linking two documents in OrientDB. This is take from documentation. Here we are adding new user in DB and connecting it to give role:
var db = orient.getDatabase();
var role = db.query("select from ORole where name = ?", roleName);
if( role == null ){
response.send(404, "Role not found", "text/plain", "Error: role name not found" );
} else {
db.begin();
try{
var result = db.save({ "#class" : "OUser", name : "Gaurav", password : "gauravpwd", roles : role});
db.commit();
return result;
}catch ( err ){
db.rollback();
response.send(500, "Error: Server", "text/plain", err.toString() );
}
}
Hope it helps you and others.
This is how to insert a Package with a linkset referring to an arbitrary number of Versions:
val version = new ODocument("Version")
.field("id", "1.0")
version.save()
val versions = new java.util.HashSet[ODocument]()
versions.add(version)
val package = new ODocument("Package")
.field("id", "MyPackage")
.field("versions", versions)
package.save()
When inserting a Java Set into an ODocument field, OrientDB understands this to mean one wants to insert a linkset, which is an unordered, unique, collection of references.
When reading the Package back out of the database, you should get hold of its Versions like this:
val versions = doc.field[java.util.HashSet[ODocument]]("versions").asScala.toSeq
As when the linkset of versions is saved, a HashSet should be used when loading the referenced ODocument instances.
Optionally, to enforce that Package.versions is in fact a linkset of Versions, you may encode this in the database schema (in SQL):
create property Package.versions linkset Version