NHibernate Envers: Auditing entity based on property value - c#

I have a very specific need for auditing.
Consider the following class (I changed the name of my classes and trimmed unnecessary code for the sake of simplicity)
[Audited]
public class Client
{
[NotAudited]
public virtual IList<Order> Orders {get; set;}
}
The Client entity should only be audited when the Orders property is NOT empty.
Is that at all possible ? If so, how I would I do it ?

If you want to turn off auditing in runtime based on some state, you can make your own custom subclass of AuditEventListenerand pass an instance of that type into IntegrateWithEnvers method.
In your subclass, you can override OnPostDelete, OnPostInsert, OnPostRecreateCollection, OnPostUpdate, OnPreRemoveCollection and OnPreUpdateCollection. In your case, you should probably check evt.Entity and evt.AffectedOwnerOrNull. If you want to audit, simply call base method, if you don't want to audit do nothing in your implementation.
Note however that you should probably just doing this if you just use Envers for simple logging. If you use it to recreate historical instances, "removing" auditing for some historical events may cause problems when loading historical instances. If that's the case for you it's only safe to do this if an entity either has or hasn't got Orders for all its lifetime.

Related

Disable possibility to update subclasses

I am developing a inheritance strategy in fluent nhibernate. Everything works correctly but I have a one question. Is there any possibility to disable updating base property through the subclass?
Here is a dummy code:
public class ObjectA
{
public virtual string StatusA { get; set; }
}
public class ObjectB : ObjectA
{
public virtual string StatusB { get; set; }
}
public class ObjectBMap : SubclassMap<ObjectB>
{
public ObjectBMap()
{
Map(x => x.StatusB);
}
}
When I am updating objectB I don't want to update StatusA. I want to change the status A when I will be updating ObjectA. Does nhibernate have this kind of feature? Does it have sense?
Edit: Additional explenation
The reason why I want to do such thing is that in my system (asp mvc application) we have two different places where we manage objectsA and objectsB. First we create object A and later we want to 'convert' object A to objectB. Then we can edit these two objects in two different modules.
My flow for editing objectB:
-Read objectB from db, convert it to viewmodel
-post form from view, convert view data from form to objectB and update in db.
I don't want to extend view model for objectB for data from object A, store this data in some hidden fields and convert from view model.
I thought that if could mark that this data couldn't be updated by Session.SaveorUpdate(objectB) it would resolve my problems. So basically that was my question.
Try to check the documentation:
5.1.3. class
Small cite:
<class
name="ClassName" (1)
table="tableName" (2)
...
dynamic-update="true|false" (7)
dynamic-insert="true|false" (8)
...
...
(7) dynamic-update (optional, defaults to false): Specifies that UPDATE SQL should be generated at runtime and contain only those columns whose values have changed.
(8) dynamic-insert (optional, defaults to false): Specifies that INSERT SQL should be generated at runtime and contain only the columns whose values are not null.
What we can see, is the setting "dynamic-update" ... which does what we would expect: update only properties which were changed
This would be the most native way how to learn NHibernate to issue updates only to the ObjectB ... if there are no changes in the ObjectA defined properties.
But in general: simply leave it up NHibernate. What it does, would most likely be the best we should require... it is a mature tool
EXTEND
Based on the question extension - I would say: do not go that way... Do not.
With ORM tools you will gain a lot, if your model, the business domain model, is kept as easy as it could be. NHibernate can help with lot of stuff e.g.:
selection of all or only some properties - called projections
paging
sorting
filtering
cascading of WRITE operations
and even more...
But it won't help you to manage the "unexpected" or "exceptional" domain model designs.
Please read this:
Composition over inheritance
Composition over inheritance (or Composite Reuse Principle) in object-oriented programming is a technique by which classes may achieve polymorphic behavior and code reuse by containing other classes that implement the desired functionality instead of through inheritance...

NHibernate many-to-one "on the fly"

I'd like to know if the next problem can be solved in a different way in NHibernate.
Let's say we've this domain:
public class A
{
public virtual B LastAssociationWithB { get; set; }
public virtual ICollection<B> CollectionAssociationOfB { get; set; }
}
public class B
{
public virtual DateTime DateAdded { get; set; }
}
The LastAssociationWithB property represents one of the B persistent objects associated in the CollectionAssociationOfB collection property.
Actually, LastAssociationWithB represents the last B persistent object added by date.
So, in the domain, when a new B is added to CollectionAssociationOfB, it's also assigned to LastAssociationWithB.
This is a good way of later turning code into less complex LINQ queries.
Anyway, my question is: do you know any other approach to this? For example, some kind of many-to-one association that produces a SQL join under the hoods so you wouldn't need to have an explicit 1:n relation in the A table but it would maintain the class property?
Or is my current approach the recommended way of solving this scenario?
Side note: in the real-world scenario that CollectionAssociationOfB is an ordered list as ordering is specified in the NHibernate mapping configuration.
You could specify the relationship using a formula:
whether this is better or not is debatable.. it depends on your circumstances - one the one hand it ensures consistency, but on the other hand it will probably have a performance penalty when querying - so it really depends on your own specific case.
Another alternative is to use a trigger on insert into B to update the column in A. This has the downside of moving logic into the database, but it would ensure consistency without the potential performance penalty.
You could also achieve the equivalent of a trigger by using an NHibernate event to intercept saving B and then updating A - with the benefit of the logic remaining in your code, but the downside that any direct updates to the database could introduce inconsistency.
Of course both trigger options obfuscate the logic somewhat, as opposed to having a method on A or B that does the logic. I would personally probably put a method in A to add a new B and update the association, but then you would need to ensure that no-one updates the B collection directly and bypasses your method.

How to use Entity Framework in Enterprise application

i have some questions of how to use the Entity Framework in an enterprise application.
First of all, i work with ADO.NET for many years now and i use objects to reflect the data that i get from the database provider.
Every time i want to change something or insert something into the database.
I just call a Save() method and get the job done.
Every object has a DatabaseManager that manage the queries to the DataAccess layer.
For example
public class Article{
public int ID{get;set;}
public string Title{get;set;}
.....
public bool Save(){
if(this.ID == -1){
return new ArticleDatabaseManager().InsertArticle(this);
}else{
return new ArticleDatabaseManager().UpdateArticle(this);
}
}
}
public ArticleDatabaseManager : DatabaseManager
{
...ADO.NET code
}
I don't know if i have to use the same architectur or change all the way i use this objects in my application.
I thought if i create something like the above i can do something like this :
public class Article{
public int ID{get;set;}
public string Title{get;set;}
.....
public bool Save(){
if(this.ID == -1){
return new ArticleDatabaseManager().InsertArticle(this);
}else{
return new ArticleDatabaseManager().UpdateArticle(this);
}
}
}
In the Each DatabaseManager implements some Link To Entities or even EntitySQL to do the same job like the old DatabaseManager does.
Fill the Business models with the values that i from the Entity Objects.
Then i could work with the Business as before and just any time i want to do some changes i communicate via EntityFramework to the Database.
Sould i implement something like the above?
Sould i just inherit the previous business objects to the entity objects?
EX :
public class Article : ArticleEntity
{
//some properties for validation etc
}
Sould i use something completely different?
I Just Don't knwo:/
I have no experience with other ORM. Just mine hand written "ORM" System.
Thank you very much.
I'm sorry for my lack of English and i know that i ask too much in a single question...
But moving from one technology to an other for a dinosaur like me is like i change Country:/
Did you at least try to use some EF tutorial? If not it is time to do that because we cannot explain you everything about EF in single answer (even in multiple - that is not purpose of SO to replace tutorials and learning materials). That should give you pretty clear answer about all your stuff related to your database managers.
In general what you did till know is very close to Active record pattern. If your objects also has static methods used to retrieve object from database it is Active record pattern. When using EF you usually don't use this pattern and you don't need any database manager. EF is build around class which is called context and this context works as your database manager for all entities you are using. It is possible to add saving and retrieval methods to entities but because it breaks separation of concerns and it makes your entities heavily dependent on EF and persistence (trend is to make them completely independent = POCO) it is usually not used.
Don't derive any custom class from entity. EF will not be able to use your derived type. Use entity mapped in EF as your class and add all custom properties and methods directly to this class (you can even create that class from scratch if you don't want to use code generators). In case of generated entities you can add custom code in partial classes. If you don't use EF entity as your object you will have to manually handle conversion from one to other (or use some tool like AutoMapper).
EF is not able to work with XML column - it will handle it as string. Especially if you plan to use these data for some ordering or filtering and if they have fixed structure you should model them as separate tables / entities. If it is really just structured content (with dynamic structure) you can use it as XML string.

Repository Pattern without an ORM

I am using repository pattern in a .NET C# application that does not use an ORM. However the issue I am having is how to fill One-to-many List properties of an entity. e.g. if a customer has a list of orders i.e. if the Customer class has a List property called Orders and my repository has a method called GetCustomerById, then?
Should I load the Orders list within the GetCustomerById method?
What if the Order itself has another list property and so on?
What if I want to do lazy loading? Where would I put the code to load the Orders property in customer? Inside the Orders property get{} accessor? But then I would have to inject repository into the domain entity? which I don't think is the right solution.
This also raises questions for Features like Change Tracking, Deleting etc? So i think the end result is can I do DDD without ORM ?
But right now I am only interested in lazy loading List properties in my domain entities? Any idea?
Nabeel
I am assuming this is a very common issue for anyone not using an ORM in a Domain Driven Design? Any idea?
can I do DDD without ORM ?
Yes, but an ORM simplifies things.
To be honest I think your problem isn't to do with whether you need an ORM or not - it's that you are thinking too much about the data rather than behaviour which is the key for success with DDD. In terms of the data model, most entities will have associations to most another entities in some form, and from this perspective you could traverse all around the model. This is what it looks like with your customer and orders and perhaps why you think you need lazy loading. But you need to use aggregates to break these relationships up into behavioural groups.
For example why have you modelled the customer aggregate to have a list of order? If the answer is "because a customer can have orders" then I'm not sure you're in the mindset of DDD.
What behaviour is there that requires the customer to have a list of orders? When you give more thought to the behaviour of your domain (i.e. what data is required at what point) you can model your aggregates based around use cases and things become much clearer and much easier as you are only change tracking for a small set of objects in the aggregate boundary.
I suspect that Customer should be a separate aggregate without a list of orders, and Order should be an aggregate with a list of order lines. If you need to perform operations on each order for a customer then use orderRepository.GetOrdersForCustomer(customerID); make your changes then use orderRespository.Save(order);
Regarding change tracking without an ORM there are various ways you can do this, for example the order aggregate could raise events that the order repository is listening to for deleted order lines. These could then be deleted when the unit of work completed. Or a slightly less elegant way is to maintain deleted lists, i.e. order.DeletedOrderLines which your repository can obviously read.
To Summarise:
I think you need to think more about behaviour than data
ORM's make life easier for change tracking, but you can do it without one and you can definitely do DDD without one.
EDIT in response to comment:
I don't think I'd implement lazy loading for order lines. What operations are you likely to perform on the order without needing the order lines? Not many I suspect.
However, I'm not one to be confined to the 'rules' of DDD when it doesn't seem to make sense, so... If in the unlikely scenario that there are a number of operations performed on the order object that didn't require the order lines to be populated AND there are often a large number of order lines associated to an order (both would have to be true for me to consider it an issue) then I'd do this:
Have this private field in the order object:
private Func<Guid, IList<OrderLine>> _lazilyGetOrderLines;
Which would be passed by the order repository to the order on creation:
Order order = new Order(this.GetOrderLines);
Where this is a private method on the OrderRepository:
private IList<OrderLine> GetOrderLines(Guid orderId)
{
//DAL Code here
}
Then in the order lines property could look like:
public IEnumberable<OrderLine> OrderLines
{
get
{
if (_orderLines == null)
_orderLines = _lazilyGetOrderLines(this.OrderId);
return _orderLines;
}
}
Edit 2
I've found this blog post which has a similar solution to mine but slightly more elegant:
http://thinkbeforecoding.com/post/2009/02/07/Lazy-load-and-persistence-ignorance
1) Should I load the Orders list within the GetCustomerById method?
It's probably a good idea to separate the order mapping code from the customer mapping code. If you're writing your data access code by hand, calling that mapping module from the GetCustomerById method is your best option.
2) What if the Order itself has another list property and so on?
The logic to put all those together has to live somewhere; the related aggregate repository is as good a place as any.
3) What if I want to do lazy loading? Where would I put the code to load the Orders property in customer? Inside the Orders property get{} accessor? But then I would have to inject repository into the domain entity? which I don't think is the right solution.
The best solution I've seen is to make your repository return subclassed domain entities (using something like Castle DynamicProxy) - that lets you maintain persistence ignorance in your domain model.
Another possible answer is to create a new Proxy object that inherits from Customer, call it CustomerProxy, and handle the lazy load there. All this is pseudo-code, so it's to give you an idea, not just copy and paste it for use.
Example:
public class Customer
{
public id {get; set;}
public name {get; set;}
etc...
public virtual IList<Order> Orders {get; protected set;}
}
here is the Customer "proxy" class... this class does not live in the business layer, but in the Data Layer along with your Context and Data Mappers. Note that any collections you want to make lazy-load you should declare as virtual (I believe EF 4.0 also requires you to make props virtual, as if spins up proxy classes at runtime on pure POCO's so the Context can keep track of changes)
internal sealed class CustomerProxy : Customer
{
private bool _ordersLoaded = false;
public override IList<Order> Orders
{
get
{
IList<Order> orders = new List<Order>();
if (!_ordersLoaded)
{
//assuming you are using mappers to translate entities to db and back
//mappers also live in the data layer
CustomerDataMapper mapper = new CustomerDataMapper();
orders = mapper.GetOrdersByCustomerID(this.ID);
_ordersLoaded = true;
// Cache Cases for later use of the instance
base.Orders = orders;
}
else
{
orders = base.Orders;
}
return orders;
}
}
}
So, in this case, our entity object, Customer is still free from database/datamapper code calls, which is what we want... "pure" POCO's. You've delegated the lazy-load to the proxy object which lives in the Data layer, and does instantiate data mappers and make calls.
there is one drawback to this approach, which is calling client code can't override the lazy load... it's either on or off. So it's up to you in your particular usage circumstance. If you know maybe 75% of the time you'll always needs the Orders of a Customer, than lazy-load is probably not the best bet. It would be better for your CustomerDataMapper to populate that collection at the time you get a Customer entity.
Again, I think NHibernate and EF 4.0 both allow you to change lazy-loading characteristics at runtime, so, as per usual, it makes sense to use an ORM, b/c a lot of functionality is provided for you.
If you don't use Orders that often, then use a lazy-load to populate the Orders collection.
I hope that this is "right", and is a way of accomplishing lazy-load the correct way for Domain Model designs. I'm still a newbie at this stuff...
Mike

Entity Framework 4 Abstract Model - How to Programatically Eager-Load Navigational Properties?

I have an EF4 Model that is built with abstract entities/classes:
Notice how State entity has a navigational property called Country.
Note: I have lazy-loading disabled, so i must eager-load on demand.
Now, if i have the following method:
public Location FindSingle(int id)
{
return _repository.Find().WithId(id).SingleOrDefault();
}
This does not return any associations by default. But how can i dynamically eager-load the associations when i explicitly want to?
I cannot do this:
return _repository.Find().WithId(id).Include("Country").SingleOrDefault();
As i am working with an abstract class called Location, which does not have a navigational property called "Country". I do not know what the derived type is until i actually execute the query with .SingleOrDefault.
So, here's what i've had to do:
public Location FindSingle(int id, bool includeAssociations = false)
{
var location = _repository.Find().WithId(id).SingleOrDefault();
return includeAssociations
? LoadAssociation(location)
: location;
}
private Location LoadAssociation(Location location)
{
// test derived-type, e.g:
var state = location as State;
if (state != null)
return _repository.Find().OfType<State>().Include("Country").WithId(id).SingleOrDefault();
}
Essentially, i'm doing 2 identical calls. Does it work? Yes. Is it pretty? No, and it's not really "eager-loading".
I know this is not the correct solution, can you guys think of the proper one? (and yes i know i can use stored procedures, but i really want to go through my repository/model here, so the entities are correctly attached to the graph, ready for editing).
Even though .Include causes a Left Outer Join, the problem is i'm working off the "Locations" entity set. I need to .Include on the "State", but "States" belong to the "Locations" entity set (derived classes belong to their parent's entity set).
So i guess my question is actually pretty generic - how do we do a .Include on a child of an abstract entity, when we don't know what the child is beforehand?
Remember, i cannot use .OfType<T>() first (and then the .Include on the derived type), as i don't know what T is (and neither does the calling code), hence generics cannot be utilized here.
The real issue here is that you are holding an Id but you don't know what it represents: it could be for a Country or for a State. At some time you presumably did know what it was, but you didn't maintain that information.
After loading a Location from the repository, how do you know which type to cast it to in order to access the relevant relationship property on it? Presumably you have to use as or is with cast and then you can access these properties. Again that kinda smells bad.
The best option here would be to maintain both the Type and the Id of a Location object so you can reload it using the appropriate repository method.
Another option would be to instead move the relationship up to the Location class so that every Location object has a .Parent Location and a .Children Locations collection. Now you can include them in your Include and when you find you have a State you know to look at .Parent and when you have a Country you know to look at .Children. Use null for no parent and an empty collection for no children. Now when you add continents or cities to your Location class you'll be in great shape to use the same model.
A final option which you can sometimes use in situations like this is to Union two queries after converting them to the common base type, e.g. something like:-
context.Locations.OfType<Country>().Include("States").Cast<Location>().Union(context.Locations.OfType<State>().Include("Countries).Cast<Location>());

Categories

Resources