Mapping to custom types in NHibernate 3.2 - nhibernate

I have just started to use NHibernate 3.2 with its new Conformist API, having used previous versions with Fluent a while back. The basic stuff seems fine but I am currently struggling with trying to map a string to a custom type.
In this specific case, I have a string which is a semi-colon separated list of roles in a column on one of my tables. When I get it out, I want it to be mapped into a "RoleSet" custom object that I have created by passing the string value from the database into its constructor.
I have created a IUserType but I cannot see how to tell it to use it.
Previously with Fluent I would have done this in my map class:
Map(x => x.Roles).CustomType<RoleSetType>();
Is there an equivalent way to do this is in the new API?

Give this a try...
Property(x => x.Roles, x => x.Type(typeof(RoleSetType), null));

Related

Omit norms in nest 2

Hi I'm upgrading to elastic 2.x using nest with c#.
I used to use the omit-norms=true as an attribute to a property, but with the new nest I can't find the equivalent.
Where is it?
In NEST 2.x, Norms can't currently be set using attribute based mapping (the property is not a primitive type, but an INorms).
You can use fluent mappings however, and mix with attribute based mapping. Here's an example that defines a mapping at the point of creating an index (you can also specify mapping using the Put Mapping API too)
var descriptor = new CreateIndexDescriptor("myindex")
.Mappings(ms => ms
.Map<Company>(m => m
// infer mappings based on POCO property types and take into
// account attribute mappings
.AutoMap()
// override certain inferred or attribute based mappings
// from Automapping
.Properties(ps => ps
.String(s => s
.Name(c => c.Name)
// omit norms equivalent in Elasticsearch >= 2.0
.Norms(n => n
.Enabled(false)
)
)
)
)
);

NHibernate QueryOver projection on many-to-one

I am trying to get a QueryOver working using a Projection on a many-to-one.
The class "Post" has a property many-to-one "Creator".
Using
session.QueryOver(Of Post).
Select(Projections.
Property(of Post)(Function(x) x.Creator).
WithAlias(Function() postAlias.Creator)).
TransformUsing(Transformers.AliasToBean(Of Post)()).
List()
works BUT each creator is retrieved by a single query rather than using a join like it is done when not using a select/projection. So if there are 5 posts with 5 different creators, 6 queries will be run 1 for the list of posts and 5 for the creators.
I tried to get it working using a JoinAlias but nothing really did the job.
I already searched for a solution, but all solutions I found did use the Linq-Provider which does not really fit since the actual "field list" is passed via a parameter.
Does anyone know if there is a solution to this other than the linq provider?
There is a solution, we can use projections for many-to-one and then custom result transformer.
DISCLAIMER: I can read VB syntax but do not have enough courage to write... I expect that you can read C# and convert it into VB....
So we can have projection like this:
// aliases
Post root = null;
Creator creator = null;
// projection list
var columns = Projections.ProjectionList();
// root properties
columns.Add(Projections.Property(() => root.ID).As("ID"));
columns.Add(Projections.Property(() => root.Text).As("Text"));
// reference properties
columns.Add(Projections.Property(() => creator.ID).As("Creator.ID"));
columns.Add(Projections.Property(() => creator.FirstName).As("Creator.FirstName"));
// so our projections now do have proper ALIAS
// alias which is related to domain model
// (because "Creator.FirstName" will be use in reflection)
var query = session.QueryOver<Post>(() => root)
.JoinAlias(() => root.Creator, () => creator)
.Select(columns)
Now we would need smart Transformer, our own custome one (plugability is power of NHibernate). Here you can find one:
public class DeepTransformer
And we can continue like this
var list = query
.TransformUsing(new DeepTransformer<Post>())
.List<Post>()
Check also this:
Fluent NHibernate - ProjectionList - ICriteria is returning null values
NHibernate AliasToBean transformer associations

Fetching a lazy loaded property in NHibernate that *isn't* a reference

I have an entity with a binary column that's set to lazy load in the mapping. In some cases, though, we want to get the entity along with the binary data at the same time. I tried using Linq.Fetch(x => x.BinaryData), but that gives an invalid join exception. Understandable, considering it shouldn't be a join in the first place. Is there a way to get this working? I'm using NHibernate 3.1
This is the mapping:
Map(x => x.BinaryData)
.CustomSqlType("image")
.Length(int.MaxValue)
.Not.Nullable()
.LazyLoad(); // Wanna make sure we don't kill the app by loading the image data when we don't need it.
This is the fetching:
Linq.Where(x => x.Id == id).Fetch(x => x.BinaryData).FirstOrDefault();
This looks like to be not possible at the moment : https://nhibernate.jira.com/browse/NH-2888
So, You have to use HQL :
var post = session.CreateQuery("from Post fetch all properties")
.SetMaxResults(1)
.UniqueResult<Post>();
Source : http://ayende.com/blog/4377/nhibernate-new-feature-lazy-properties
In HQL you can use fetch all properties to eagerly load lazy property. But in NH3.1 it is not yet implemented for Linq queries. As I know this bug is in NHibernate Jira so you can check if it is resolved or you can fix it yourself. For our company prototype i fixed this bug, but I did so in very brute-force way so i didn't send patch to NHibernate project

Fluent Nhibernate problem

I have this in my entity:
public virtual Iesi.Collections.Generic.ISet<long> Blas { get; set; }
and this for my mapping:
mapping.HasMany(x => x.Blas).AsSet().Element("Value", m => m.Type<long>());
This creates the relevant tables and I add data like this:
X.Blas = new Iesi.Collections.Generic.HashedSet<long>();
X.Blas.Add(some_long);
This adds values to the object but the values in Blas are never persisted (everything else of X is).
Can anyone see anything wrong?
Thanks.
Christian
if X is loaded through a session then blas is initialized with a changetracking collection. So dont overwrite it. Try X.Blas.Clear(); instead of X.Blas = new Iesi.Collections.Generic.HashedSet<long>();
Try adding a cascade setting.
mapping.HasMany(x => x.Blas).AsSet()
.Element("Value", m => m.Type<long>())
.Cascade.AllDeleteOrphan();
Also you should just be able to use ICollection and a regular Hashset instead of Iesi. Provided you're using at least version 3 (it might work with 2.1.2 or higher as well)
You should follow proper object oriented encapsulation to avoid problems like this, an example in my post here: How do I map a collection accessed through a read only property?

How do I use Fluent Nhibernate many-to-many for optimal performance?

I have a product table that has a many-to-many relation to itself (using a two-column many-to-many table) and I have set it up in Fluent NHibernate with the following code:
public class ProductConfiguration : ClassMap<Product>
{
public ProductConfiguration()
{
Table("Product");
Id(p => p.Id).GeneratedBy.Guid();
Map(p => p.Name).Not.Nullable().Length(254);
Map(p => p.Description).Not.Nullable().Length(1000);
Map(p => p.CreatedAt).Not.Nullable();
HasManyToMany(p => p.CrossSell)
.Table("ProductCrossSell")
.ParentKeyColumn("Id")
.ChildKeyColumn("ProductId");
}
}
My MVC application has two pages that uses this setup:
Index - Uses a generic repository GetAll method to display all products.
Detail - Uses a generic repository GetById method to display one product and any related cross sell products setup in the many-to-many realation.
It looks like NHibernate is set to LazyLoad the many-to-many by default so when I fire up the application and watch it in profiler I can see that it does LazyLoad the many-to-many with the following alert "Use of implicit transactions is discouraged".
How do I get rid of this alert? I couldn't find any information on how to wrap a LazyLoad inside a transaction to get rid the alert. Is it even possible?
Is there a way to not lazyload this by telling NHibernate that whenever I ask for GetById make sure to join the tables a get everything in one query? I tried using .Fetch.Join() in the many-to-many mapping but that also affected my GetAll query which now displays a joined result set as well which is incorrect.
What is the best apprach for this kind of simple scenario?
Thanks
The way to get rid of the warning is to access the object graph and fully populate the UI elements inside a single transaction.
Not by configuration. You can create an HQL query that eager fetches the association and use that query for a specific view. I would stick with lazy loading and not make that optimization unless needed. The HQL would be:
return session.CreateQuery("from ProductionConfiguration pc join fetch pc.CrossSell where pc.Id = ?")
.SetGuid(0, id)
.List<ProductConfiguration>();
All collections are lazily loaded in NHibernate by default.
You must be triggering loading with a call of some kind (maybe even with the debugger watches)