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)
)
)
)
)
);
Related
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
When using ReferencesAny<> there is .EntityTypeColumn("MyType") which is not visible to application.
Is there option to query by that column using HQL or something and how to integrate into my LINQ to HQL queries?
As always, NHibernate has solution for (almost) everything.
Let's assume mapping like this (ala documentation):
ReferencesAny(x => x.AnyEntity) // the property name is AnyEntity... used below
// some explicit mapping
.AddMetaValue<Household>(typeof(Employee).Name)
.AddMetaValue<Client>(typeof(Contact).Name)
// the essence of <any>
.EntityTypeColumn("MyType")
.EntityIdentifierColumn("TheId")
.IdentityType<int>();
A cite from doc: 14.7. The where clause:
Likewise, the special property class accesses the discriminator value of an instance in the case of polymorphic persistence. A .Net class name embedded in the where clause will be translated to its discriminator value.
So, now we've informed NHibernate, that the colunn MyType contains the type, the equiv of the C# type. Because we can access EntityTypeColumn via the .class - this query will give us what we want:
// the 'Contact' represents the value contained in DB...
var hql = "from MyEntity where AnyEntity.class = 'Contact' ";
...
session.CreateQuery(hql)
.List<MyEntity>();
this will generate the WHERE ... MyType = 'Contact'
The same in the QueryOver:
var query = session.QueryOver<MyEntity>()
.Where(x => x.AnyEntity is Contact)
.List<MyEntity>();
NOTE: the bad news, that with built in LINQ provider, similar query is failing. I would guess it is a bug. I.e. this is not working session.Query<MyEntity>().Where(x => x.AnyEntity is Contact), generating the wrong WHERE clause
EXTENDED as asked in the comment
We can also filter by the <any> elements ID, the 'EntityIdentifierColumn'
The syntax would look like this (see the magical ".id" selector")
query
...
.Where(Restrictions.In("AnyEntity.id", new[] {1, 2, 3, 4, 5, 6, 7, 8}))
...
How about simply mapping the column in the entity you reference. Have a base class for all kind of types for example?
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.
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>();
};
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));