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.
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
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 an error "The column 'Translat2_' was specified multiple times for 'query'" when using paging for my query.
My classes hierarchy:
Politician
--PoliticianInFactions : PoliticianInFaction
--EntityTranslations : Translation
Faction
--PoliticiansInFaction : PoliticianInFaction
--EntityTranslations : Translation
Translation
--Name : String
--Language : Language
What I want: to fetch politicians ordered by its faction's name and than by its name.
My query:
var criteria = Session.CreateCriteria<Politician>("politician");
// criteria for current faction
var currentFactionCriteria = criteria
.CreateCriteria<Politician>(x => x.PoliticianInFactions, JoinType.InnerJoin)
.Add<PoliticianInFaction>(x => x.FromDate <= DateTime.Now)
.CreateCriteria<PoliticianInFaction>(x => x.Faction, JoinType.InnerJoin);
// add order by faction's name !!!
currentFactionCriteria
.CreateCriteria<Faction>(x => x.EntityTranslations, JoinType.InnerJoin)
.Add<Translation>(x => x.Language.Id == languageId)
.AddOrder<CityTranslation>(x => x.Name, Order.Asc);
// add order by politician's name !!!
criteria
.CreateCriteria<Politician>(x => x.EntityTranslations, JoinType.InnerJoin)
.Add<Translation>(x => x.Language.Id == languageId)
.AddOrder<Translation>(x => x.Name, Order.Asc);
When adding paging to this query I have an error. Without paging everything is OK. Also if I comment(remove) any block marked with (!!!) exception dissapears.
What am I doing wrong? If this is a bug of NHibernate give me some workaround please. Thank you.
Check you mapping files to see if you have mapped multiple properties to the same database column or mapped the same databases column to multiple properties.
I know that this is an ancient thread, but this issue plagued me recently.
I've discovered that the case of the property calls in your mapping matters relative to paging. I.E. if you have a property with a column called "field" and you map it to another property as well, this will not be an issue if the case of field is the same.
However, if you identify your other mapping with a column called "Field", paging will not know that this is not a distinct property and will try to query the same column twice!
I guess that you have a CASE or duplicate problem.In my issue I have the following situation:
I take the column "serie id" two times but in different ways.. I put "S" in lower and in upper.. I hope that helps..
I have a simple model class (Part), which pulls from it's information from a single table (t_Part).
I would like a subclass of this model called (ProducedPart), that would still utilize NHibernate's caching mechanisms, but would only be instances of (Part) that have a foreign key relationship in a table called "t_PartProduction". I do not need to have a model for this second table.
I only need a read-only version of ProducedPart
I could always implement a Facade/Repository over this, but I was hoping to setup a mapping that would pull "t_Part" joined with "PartProduction" when I asked for "ProducedPart" in NH.
Is this the wrong way to use NH?
Edit
So, the SQL would look something like
SELECT p.*
FROM t_Part p
INNER JOIN t_PartProduction pp ON pp.PartID = p.PartID
WHERE pp.ProductionYear = '2009'
I believe what you are looking for is a joined subclass. In FNH, it will look something like:
public class PartMap : ClassMap<Part>
{
public PartMap()
{
Id(x => x.Id)
JoinedSubClass<ProducedPart>("PartID", sub => {
sub.Map(x => x.Name);
sub.Map(x => x.ProductionYear);
});
}
}
In order have NHibernate cache the results, you will need to have the subclass mapped (and if you didn't map it, you wouldn't be able to get NH to load it in the first place).
Bringing in some context from the FNH groups thread, it will not explicitly be read-only though. In my opinion, making things read-only is not an appropriate thing for NHibernate to manage. This is better controlled by the database and connections (i.e. creating a connection to the database that only has SELECT permissions on the tables/views being accessed). See my answer to a previous SO question about readonly sessions in NHibernate for more of my thoughts on the matter.
The key here is using both the where and mutable elements of the class definition for NHibernate Mappings.
Using Fluent NHibernate, this looks like:
public Part()
{
WithTable("t_Part");
Id(i => i.Id).ColumnName("PartID");
Map(m => m.Name).ColumnName("Part");
SetAttribute("where", "PartID IN ( SELECT pp.PartID FROM t_PartProduction pp WHERE pp.ProductionYear = '2009' ) ");
ReadOnly();
}
No, this is perfectly possible. Look in the NHibernate documentation for the "table per subclass" model of inheritance. It will actually implement this as a LEFT JOIN, so that when you load a Part, it creates an instance of either your Part or your ProducedPart class depending on whether the other row is present. You'll find documentation on nhibernate.info.
I'm not sure you could make ProducedPart read-only doing this though.
I'm assuming from this:
WHERE pp.ProductionYear = '2009'
that you want the subclass only where the production year is 2009, i.e. if when there is a record in t_PartProduction for a different year, you want this Part treated as a plain Part object, not a ProducedPart, then you could consider creating a view definition within your database that is a filtered version of t_PartProduction, then making your subclass join to this view rather than the base table.