NHibernate mapping by code: Mapping userTypes by convention - nhibernate

I would like to know how to configure NHibernate "mapping by code" so that when I map a property of a certain type, it uses a certain userType to perform that mapping. It figures this out by convention.
For example, if I have an Account class with a property Currency of type Currency, then the NHibernate configuration should figure out (by convention) that it needs to use the CurrencyUserType to perform the mapping.
I'm unable to find the relevant documentation for this, so if such documentation does exist, then a few links will be appreciated too.
Note: This is not a FluentNHibernate question.

var mapper = new ConventionModelMapper();
mapper.IsProperty((info, b) => b || info.GetPropertyOrFieldType() == typeof(Currency));
mapper.BeforeMapProperty +=
(inspector, member, customizer) =>
{
if (member.LocalMember.GetPropertyOrFieldType() == typeof(Currency))
customizer.Type<CurrencyUserType>();
};

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

NHibernate (Fluent mapping) ReferencesAny<object>

Base entity interface is IEntity which requires only "object ID {get;set;}" to be implemented.
Now, in almost every case ID is of Guid type (except for membership etc).
I am using following code to do mapping of interface
...
AnyPart<IEntity> primaryMap = ReferencesAny(x => x.Primary)
.IdentityType<object>() // tried with .IdentityType<Guid>()
.EntityIdentifierColumn("PrimaryID")
.EntityTypeColumn("PrimaryType")
.MetaType<string>();
...
Of course, next I am adding meta values.
So, Now getting error
Source array was not long enough. Check srcIndex and length, and the array's lower bound
And with .IdentityType<Guid>()
could not resolve property: Primary.ID of: Founder.Connection [.SingleOrDefault[Founder.Connection](NHibernate.Linq.NhQueryable`1[Founder.Connection], Quote((x, ) => (OrElse(AndAlso(Equal(x.Primary.ID, 35c2142a-4c17-4b77-96fd-a2570028a211), Equal(x.Secondary.ID, 35c2142a-4c17-4b77-96fd-a2570028a211)), AndAlso(Equal(x.Secondary.ID, 35c2142a-4c17-4b77-96fd-a2570028a211), Equal(x.Primary.ID, 35c2142a-4c17-4b77-96fd-a2570028a211))))), )]
UPDATE:
I tried also with .IdentityType(x=>x.ID) but same problem (Source array was not long enough)
UPDATE II:
Query (Actually whole method containing query) that this error occurs on is bellow:
public IQueryable<Connection> GetConnections(IEntity connectable)
{
IQueryable<Connection> query =
Query().Where(
x => x.Primary.ID == connectable.ID || x.Secondary.ID == connectable.ID);
return query;
}
Try this in the query: x.Primary == connectable (without ID).
The problem is that you reference an object (or another unmapped type, that's why you need an any mapping). There is no ID on object.
By the way, using HQL would allow you to access the id by using the keyword id, which is not available in Linq (technically it could be made available as extension method, but I don't know Linq to NH good enough to say if it had been implemented). Every any reference conceptually has an id and a class.

NHibernate: How to get mapped values?

Suppose I have a class Customer that is mapped to the database and everything is a-ok.
Now suppose that I want to retrieve - in my application - the column name that NH knows Customer.FirstName maps to.
How would I do this?
You can access the database field name through NHibernate.Cfg.Configuration:
// cfg is NHibernate.Cfg.Configuration
// You will have to provide the complete namespace for Customer
var persistentClass = cfg.GetClassMapping(typeof(Customer));
var property = persistentClass.GetProperty("FirstName");
var columnIterator = property.ColumnIterator;
The ColumnIterator property returns IEnumerable<NHibernate.Mapping.ISelectable>. In almost all cases properties are mapped to a single column so the column name can be found using property.ColumnInterator.ElementAt(0).Text.
I'm not aware that that's doable.
I believe your best bet would be to use .xml files to do the mapping, package them together with the application and read the contents at runtime. I am not aware of an API which allows you to query hibernate annotations (pardon the Java lingo) at runtime, and that's what you would need.
Update:
Judging by Jamie's solution, NHibernate and Hibernate have different APIs, because the Hibernate org.hibernate.Hibernate class provides no way to access a "configuration" property.

Querying unmapped properties in nhibernate

I am working with Linq-To-NHibernate. I need to use some properties that is not mapped to columns.
For example
Repository<Person>
.Find()
.Select(p => new PersonModel() { Id = p.Id, FullName= p.FullName,Position = p.Position });
The position is not a mapped property, it contains some logic.
I got unmapped property error.
Thanks.
Not possible, and not likely to be supported in short term.