Is it possible to configure Hiberate/NHibernate not to use the default constructor to create objects when reading from the database?
When Hibernate reads 10 customers from a table, it creates 10 Customer objects. It does this by
Customer c = new Customer();
Can I tell Hibernate to do the following instead:
Customer c = ACertainStaticFactory.CreateNewCustomer();
or even to manage a factory instance:
ACertainFactory factory = .....;
Customer c = factory.CreateNewCustomer();
or even more sophisticated, to pass a parameter which I set before:
// My client code
Query query = session.CreateQuery(...);
// either:
query.SetSomeParameter(someObject);
// or:
session.SetSomeParameter(someObject);
query.List();
// Hibernate should then behave like this:
Customer c = new Customer(someObject);
// or
Customer c = ACertainStaticFactory.CreateNewCustomer(someObject);
// etc.
Is that possible in anyway? If yes: How? If no: Is there an alternative?
When Hibernate reads 10 customers from a table, it creates 10 Customer objects. It does this by (...)
More precisely, Hibernate uses Class<T>#newInstance() to create new instances of an entity, which relies on the no-arg constructor. Hence the need to provide it.
Is that possible in anyway? If yes: How? If no: Is there an alternative?
Your requirement looks close to the Possible to have Hibernate hydrate objects with Factory? thread on Hibernate's forums so I'll quote Steve's answer (updated to match current names):
This is totally doable. In fact you
have two options:
create a custom EntityPersister implementation;
create a custom Interceptor implementation, specifically the
Interceptor.instantiate() method will
be of interest to you...
I think I'd go the interceptor way (not sure about your complex scenario but implementing the factory approach looks pretty easy).
Check this out, may be helpful:
http://fabiomaulo.blogspot.com/2008/11/entities-behavior-injection.html
Related
This is EF4. I have a SIMPLE question. Say if I add a few sales orders to the context object like:
Dim NewOrder = context.SalesOrders.CreateObject()
NewOrder.Number= 123
context.SalesOrders.AddObject(NewOrder)
I haven't called SaveChanges() yet and want to see if there's an order with Number=123 in the context using this:
context.SalesOrder.FirstOrDefault(Function(x) x.Number=123)
Why in the world does this above query return Nothing? Is it searching the database instead of the local context object?
You can search the local entities through the object state manager: (C# syntax, but the VB.NET equivalent should be obvious for you)
context.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified | EntityState.Unchanged).Select(entry => entry.Entity).OfType<SalesOrder>()
That is actually what DbSet.Local does behind the scenes too. It may be worth the effort to make this available on your context as a generic helper function.
Is Number the primary key on the SalesOrder entity?
If so, you can just use .Find() as this first queries the local entities and only then queries the database if nothing is found in the local entities collection :
context.SalesOrders.Find(number);
Note that find can only accept the primary key and not lambdas as with other LINQ operations.
Currently I am working partly with cfwheels and its Active Record ORM (which is great), and partly raw cfml with its Hibernate ORM (which is also great).
Both work well for applicable situations, but the thing I do miss most when using CF ORM is the model.update() method that is available in cfwheels, where you can just pass a form struct to the method, and it will map up the struct elements with the model properties and update the records.. really good for updating and maintaining large tables. In CF ORM, it seems the only way to to update a record is to set each column individually, then do a save. Is this the case?
Does cf9 ORM have an Active Record type update() (or equivalent) method which can just receive a struct with values to update and update the object without having to specify each one?
For example, instead of current:
member = entityLoadByPK('member',arguments.id);
member.setName(arguments.name);
member.setEmail(arguments.email);
is there a way to do something like this in CF ORM?
member = entityLoadByPK('member',arguments.id);
member.update(arguments);
Many thanks in advance
In my apps I usually create two helper functions for models which handle the task:
/*
* Get properties as key-value structure
* #limit Limit output to listed properties
*/
public struct function getMemento(string limit = "") {
local.props = {};
for (local.key in variables) {
if (isSimpleValue(variables[local.key]) AND (arguments.limit EQ "" OR ListFind(arguments.limit, local.key))) {
local.props[local.key] = variables[local.key];
}
}
return local.props;
}
/*
* Populate the model with given properties collection
* #props Properties collection
*/
public void function setMemento(required struct props) {
for (local.key in arguments.props) {
variables[local.key] = arguments.props[local.key];
}
}
For better security of setMemento it is possible to check existence of local.key in variables scope, but this will skip nullable properties.
So you can make myObject.setMemento(dataAsStruct); and then save it.
There's not a method exactly like the one you want, but EntityNew() does take an optional struct as a second argument, which will set the object's properties, although depending on how your code currently works, it may be clunky to use this method and I don;t know whether it'll have any bearing on whether a create/update is executed when you flush the ORM session.
If your ORM entities inherit form a master CFC, then you could add a method there. Alternatively, you could write one as a function and mix it into your objects.
I'm sure you're aware, but that update() feature can be a source of security problems (known as the mass assignment problem) if used with unsanitized user input (such as the raw FORM scope).
I'm in the process of early research to replace EF with NHibernate in a system that is implemented using a custom written app engine.
The client creates an entity say, Person, gets the property values from the user and sends it to the server. In the server, we used context.CreateObject<Person>() to obtain a proxy of a Person.
Then the property values where applied to the proxy and we were able to Use Lazy loading to access related objects. For instance, if the person had a property MajorID and a navigation property Major, we set MajorID to 5 and if an expression accesses Major, the correct Major is lazily loaded into this field. A similar process happens for updates.
In NHibernate, I don't have a CreateOject<>() method, so the object I have is not proxied, and therefore lacks Lazy-Loading. Also, in Update, if I Change MajorID and then access Major, it still points to the old, wrong Major.
I'm quite new to NHibernate, can I have it behave like EF in this scenario?
Thanks
You don't need CreateObject at all in NHibernate.
The implementation of proxies in NH is completely different from EF, and it's based on entities, not properties.
Here's how this would work in NH:
var person = new Person(); //no proxy needed; person is a new entity
person.Major = session.Load<Major>(majorId); //creates Major proxy, no DB call
//...somewhere else
var majorId = person.Major.Id; //getting the Id does not cause loading, ever
var foo = person.Major.Foo; //this causes lazy-loading if not already loaded.
An interesting thing to note is that there is no MajorId property, nor there is need for one, because unlike EF, you can create proxies for already persisted entities.
I think you can achieve wat you use by session.Get<> and passing the ID of the person you want to load. For the id part, you generally should not works with it directly when you maniulate associations. Why dont you just try something like:
var p = session.Get<Person>(personId);
p.Major = session.Get<Majors>(mayorId);
session.Update(p);
I need to create DTOs from NHibernate POCO objects. The problem is that the POCO objects contain dynamic proxies, which should not be copied to the DTO. I eager load all the collections and references I need to transfer in advance, I don't want NHibernate to start loading referenced collections which I did not load in advance.
Several similar questions on SO received answers which either:
Suggest Session.GetSessionImplementation().PersistenceContext.Unproxy();
Suggest turning off Lazy Loading.
In my case the first suggestion is irrelevant, as according to my understanding it causes eager loading to replace the proxies. In reality, it doesn't even work - it doesn't remove the proxies in my objects. (Any explanation why?)
The second suggestion, turning off lazy loading seems to cause all references and collections to eager load, basically loading the entire DB. My expectation was that if lazy loading is off, and I have not requested a collection, it will not be loaded. (Am I correct that NHibernate offers no such option?)
I am using NHibernate 3.3.1 with fluent configuration.
To reiterate my main question, I need to create DTOs clean of proxies, copied from POCOs which contain proxies, and I don't want to load the data behind those proxies.
Any helpful suggestion which includes example code and automates the process with ValueInjecter / AutoMapper will be immensely helpful.
Edit #1:
Following Roger Alsing's suggestion to use projections, I realized that what I'm actually looking for is a ValueInjecter-like convention based mapping. Here is why. Initially, my DTOs will be defined the same as the model's POCOs. This is due to a large code base which depends on the existing POCOs being transferred on the client-side project.
Using projections, I will have to specify which subset of fields have to be copied, and this subset may be different in each context (as, ideally, a DTO would differ). This will mean a lot of new code introduced to the server side, when there should be the second option.
Using ValueInjecter, I will be able to populate the DTOs by convention in one call, without writing specific projections, or having to maintain those into the future. That is, if I am able to have ValueInjecter ignore Proxy objects.
Given that using projections is a good but not ideal solution in my situation, is there a way to configure something like ValueInjecter to copy POCOs without copying proxies or triggering eager/lazy loads on copy?
I solve this by selecting DTO's as projections using Linq or whatever query language the O/R Mapper may have.
e.g.
return from c in customers
select new CustomerDTO
{
Name = c.Name ,
Orders = c.Orders.Select (o => new OrderDTO {...} )
};
This way, you don't need to resort to reflection magic or any other fancy stuff.
And the query fetches exactly what you need in one go, thus, this is usually much more efficient than fetching entities and then transforming them to DTO's in mem.
(it can be less efficient in some cases incase the resulting SQL query contains extra joins for whatever reason..)
I'm using the following ValueResolver with AutoMapper:
/// <summary>
/// ValueResolver that will set NHibernate proxy objects to null, instead of triggering a lazy load of the object
/// </summary>
public class IgnoreNHibernateProxyValueResolver : IValueResolver
{
public ResolutionResult Resolve(ResolutionResult source)
{
var prop = source.Type.GetProperty(source.Context.MemberName).GetValue(source.Value, null);
var proxy = prop as INHibernateProxy;
if (proxy != null && proxy.HibernateLazyInitializer.IsUninitialized)
{
return source.Ignore();
}
return source.New(prop);
}
}
for ValueInjecter solution I recommend using SmartConventionInjection (you need to copy the code from the linked page into your solution)
and after specify a convention that won't touch the proxy properties
here's a start:
public class MapPoco: SmartConventionInjection
{
protected override bool Match(SmartConventionInfo c)
{
return c.SourceProp.Name == c.TargetProp.Name;
}
}
Take a look on Projections in Introduction to QueryOver in NH 3.0
CatSummary summaryDto = null;
IList<CatSummary> catReport =
session.QueryOver<Cat>()
.SelectList(list => list
.SelectGroup(c => c.Name).WithAlias(() => summaryDto.Name)
.SelectAvg(c => c.Age).WithAlias(() => summaryDto.AverageAge))
.TransformUsing(Transformers.AliasToBean<CatSummary>())
.List<CatSummary>();
I am taking over a project that was written by third party consultants who have already left.
I come from EF backgournd. One of the DAO class has the following which I find very hard to get my head around on details of what is exactly happening step by step. If anyone could kindly help me to understand this code section will be much appreciated.
return HibernateTemplate.Execute(
delegate(ISession hbSession) // <<--What is this code actually trying to do?
{
string queryText = "from {0} x where x.Code = :Code";
queryText = string.Format(queryText, typeof(Product));
IQuery query = hbSession.CreateQuery(queryText);
query.SetParameter("Code", productCode);
query.SetCacheable(true);
query.SetCacheRegion(CoreCacheConstants.ProductQueryCacheRegion); // <-- What is this code trying to do.
var fund = query.UniqueResult(); // <-- Is this similar to DISTINCT keyword in LINQ?
if (fund == null)
throw new ArgumentException(String.Format("No product found with productcode: {0}", productCode: ));
NHibernateUtil.Initialize(((Product)Product).Details); // <--What is this code trying to do. And where is the execute method for above queries.
return fund;
}
) as Product
Basically I am confused with delegate part and why delegate is being used instead of simple query to database. And what is the benefit of above approach.
Also I cant see any nHibernate ORM mapping xml. Does Spring.NET requires mapping files in order to pass data from/to data source?In order words how does ISession knows which database to connect to and which table to use etc
This is what in the spring documents is referred to as Classic Hibernate Usage. It is not the currently recommended approach to work with NHibernate, which is described in the chapter on object relational mappers.
The "convenient" usage of delegates here is basically done to provide the HibernateTemplate the means to manage a session and hand this managed session over to other custom methods (in this particular case an anonymous method). (I think it's an implementation of the visitor pattern, btw).
Using this approach, the classic HibernateTemplate can provide functionality to methods it doesn't "know of", such as opening and closing sessions correctly and participating in transactions.
The query is actually being executed by HibernateTemplate.Execute(myMethod); I imagine it creates and initializes a session for you, does transaction management, executes your method with the managed session and cleans everything up.
I've never used HibernateTemplate, but I'm sure it would require mapping files and a SessionFactory, so if this code is hit during execution and doesn't throw any exceptions, the configuration for those has to be there somewhere!
With respect to the questions (besides the delegate part) within your posted code: the use of NHibernateTemplate hasn't really got anything to do with it: you can just as well run this code in any piece of code where you've got hold of a valid ISession instance:
the session executes a HQL query; this query is added to the query cache. I've never used SetCacheRegion myself, but apparently it gives you "fine-grained control over query cache expiration policies".
query.UniqueResult
NHibernateUtil.Initialize