Nice work!

When querying audited entities, quite often both entity type _and_ revision 
type is involved. Revision number is mandatory on revision type and the way you 
add this to the query by adding an extension method is good enough if only 
querying for revision number. However, when having a custom revision type 
(which I guess most projects have) with, for example, ModifiedBy and ModifiedAt 
you often want to make queries based on these properties.
To get some type safe way to make queries, I think the revision type needs to 
be included in the query somehow.

<<
This type information could be parsed from Envers (?) but I donot know enough 
about Envers. Are types dynamically generated at startup?
>>

I’m not sure I understand but if you ask what CLR type audited entities are 
mapped to, it is simply an IDictionary. No new CLR types are created for 
audited entities (except for their collection proxies). When 
IntegrateWithEnvers is called on NH’s Configuration object, new mappings are 
added for each mapped entity. These mappings don’t have any class mapped to 
them (in hbm mapping, the class element doesn’t have any name attribute – only 
entity-name).
When envers query API is called, this data/dictionary is “transformed” into 
entity objects (and, possibly, a revision entity).

/Roger



From: [email protected] 
[mailto:[email protected]] On Behalf Of Peter Schojer
Sent: den 30 september 2015 13:17
To: nhibernate-development <[email protected]>
Subject: [nhibernate-development] Envers.Linq (and HQL+ full Criteria support): 
First prototype

I recently started a project to extend Envers with common Nhibernate querying 
functionality like HQL, Criteria or linq.
The goal is to make querying between  history and current as transparent and 
easy as possible.
The current implementation is nowhere complete but with a few days of work I am 
already able to use HQL, Criteria and Linq to query Envers.
To make further progress and overcome some of the shortcomings I could need 
some help though :-)

Linq Query example:

var query = Session.Query<User>().Where(x => x.Name == User1Version2Name && 
x.Addresses.Count > 0).ToList(1);

For Linq I added a ToList(int versionNumber) extension method. Providing a 
versionNumber lower equal 0 executes queries against the current tables, 
otherwise AuditTables are queried.
Nice and simple. No need to write queries twice for Envers and Nhibernate.
Similar overloads exist for Criteria and HQL (QueryOver not done yet):

var query = Session.CreateCriteria<User>().Add(Restrictions.Eq("Name", 
"test")).List<User>(1);
var query = Session.CreateQuery("Select Id from User where Name = 
:name").SetParameter("name", User1Version2Name).List<int>(1);

How does it work:
The current implementation uses an interceptor to rewrite the generated sql 
from current tables to audit tables.
Biggest advantage:
- simple and easy to implement, no need to write own Linq provider
- makes use of Nhibernates Linq provider, benefits from any future work/bugfix 
done there

Biggest disadvantage:
- executed SQL and returned data types (object + proxies!) do not match the 
data types from the expression tree

Take this Query example: Session.Query<User>().Where(x => x.Name == "name2" && 
x.Addresses.Count > 0).ToList(1);

We build up an expression tree for table User. In reality we are returning an 
AuditUser object with Version=1 (Version is part of the key).
Those two types are unrelated (and also all proxy types created when evaluating 
a record).
I am currently searching for a way to fix that.

First idea, an expression tree visitor rewriting data types.
This type information could be parsed from Envers (?) but I donot know enough 
about Envers. Are types dynamically generated at startup?
Or does envers simple uses a generic type containing two properties: 
RevisionInfo Rev, TObject Obj.
That would make rewriting the query impossible.

Also dynamically changing the types after the SQL was generated is (I think) 
not possible for interceptors.
Or maybe somehow intercept proxy/object generation?

As a workaround, I have some ugly reflection hacks in place which guarantee 
that returned objects/created proxies are never cached in a session.
So all version queries behave as if they are executed on a stateless session 
(try to access a proxy object -> exception).
This at least prevents errors due to caching.

But I'd really prefer to get rid of those hacks :-)

SourceCode is attached. VS2013 project. Just let Nuget restore the packages, 
then adapt your connectionString in Setup/Globals.cs and see unit tests for 
example usage.

best regards,
Peter

--

---
You received this message because you are subscribed to the Google Groups 
"nhibernate-development" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to 
[email protected]<mailto:[email protected]>.
For more options, visit https://groups.google.com/d/optout.

-- 

--- 
You received this message because you are subscribed to the Google Groups 
"nhibernate-development" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to