Fluent Nhibernate Composite Key Not Generating Joins For Referenced Entities - nhibernate

I have a mapping with a composite key as below:
CompositeId()
.KeyReference(x => x.CreatedBy, "member_key")
.KeyReference(x => x.Box, "box_key");
This works fine for simple gets and inserts, however it is not generating joins with the tables mentioned in the reference where I try and use them as part of a query.
So this:
return _sessionFactory.GetCurrentSession().QueryOver<BoxMember>()
.Where(x => x.Box.Id == boxId)
.Where(x => x.Member.DeletedDate == null)
.Fetch(x => x.Box).Eager
.Fetch(x => x.CreatedBy).Eager
.List();
Generates the following SQL:
SELECT this_.member_key as member1_5_0_,
this_.box_key as box2_5_0_
FROM box_member this_
WHERE this_.box_key = '2750e160-ba72-4a70-b554-9fd600e3cfd0' /* #p0 */
and m1_.deleted_date is null;

I had exactly the same issue. Adding Reference mapping helped, but the issue makes no sense anyway:
Try this:
CompositeId()
.KeyReference(x => x.CreatedBy, "member_key")
.KeyReference(x => x.Box, "box_key");
Reference(x => x.CreatedBy);
Reference(x => x.Box);

Related

SubQuery nHibernate without collection

For example:
Tree treeAlias = null;
var nonRottenApples = QueryOver.Of<Apple>()
.Where(a => !a.IsRotten)
.Where(a => a.Tree.Id == treeAlias.Id)
.Select(x => x.Id); // <- optional
return NHibernateSession.QueryOver(() => treeAlias)
.Where(t => t.Id.IsIn(ListOfTreeId))
.WithSubquery.WhereExists(nonRottenApples)
.List();
How do SubQuery not collection in Apple ?
I'm researching at various locations, but i not find results for my question.
All results are collections.
My interpretation of your question is that you're trying to query for the trees that don't have rotten apples.
I believe this will work:
var rottenTreeIds = QueryOver.Of<Apple>()
.Where(apple => apple.IsRotten)
.Select(a => a.Tree.Id);
return NHIbernateSession.QueryOver<Tree>()
.Where(t => t.Id.IsIn(ListOfTreeId))
.WithSubquery.WhereProperty(t => t.Id).NotIn(rottenTreeIds)
.List();

Fluent NHibernate custom types with composite key that is used as reference to another table

I am working with legacy database and trying to create map with certain tables.
Theres profile for user, profile has reference to contact channel. However, in database key for user is composite key. This is somewhat ok, but theres some magic strings in database which should be nice if they can be converted to more typed versions.
In profile map:
CompositeId()
.KeyProperty(x => x.ServiceId, "SERVICE_ID")
.KeyProperty(x => x.Direction, "DIRECTION").CustomType<DirectionConverter>()
.KeyReference(x => x.Channel, new string[] { "CHANNEL_ID", "CONTACT_TYPE", "DIRECTION", "SERVICE_ID" })
.KeyProperty(x => x.ContactType, "CONTACT_TYPE")
.KeyReference(x => x.Agent, "AGENT_ID");
Problem is line:
.KeyReference(x => x.Channel, new string[] { "CHANNEL_ID", "CONTACT_TYPE", "DIRECTION", "SERVICE_ID" })
(So channel has composite key also ...)
In that reference i don't know how to tell fluent nhibernate to use converter for "DIRECTION" column handling. In practise this can be seen as that converter will receive null value on NullSafeSet.
Is there existing solution for this or is only option not to use converters for this kind of columns?
Solved.
Mapping was incorrect.
CompositeId()
.KeyProperty(x => x.ServiceId, "SERVICE_ID")
.KeyProperty(x => x.Direction, "DIRECTION").CustomType<DirectionConverter>()
.KeyReference(x => x.Channel, new string[] { "CHANNEL_ID", "CONTACT_TYPE", "DIRECTION", "SERVICE_ID" })
.KeyProperty(x => x.ContactType, "CONTACT_TYPE")
.KeyReference(x => x.Agent, "AGENT_ID");
Correct version:
CompositeId()
.KeyReference(x => x.Channel, new string[] { "CHANNEL_ID", "CONTACT_TYPE", "DIRECTION", "SERVICE_ID" })
.KeyReference(x => x.Agent, "AGENT_ID");
Now i can use ChannelId, ContactType, Direction, ServiceId, AgentId as composite key in this class. Incorrect converter was symptom of this problem but error messages were very misleading one.

nHibernate joining multiple tables and using AliasToBean Transformer

I have a very basic need to get some data from the database and return a DTO. I found that joining multiple tables using nHibernate and "projecting" so to say, to a DTO to be quite a bit of code. After looking at several examples, most which didn't work leaving me a DTO with null values, I cam up with the following and was wondering if you nHibernate ninja's out there could tell me if there is a better way.
public IOpenIdUser GetOpenIdUser(string claimedIdentifier, IOpenIdUser openIdUserDto)
{
User user = null;
OpenIdUser openIdUser = null;
Profile profile = null;
UserType userType = null;
return
SessionWrapper.Session.QueryOver(() => user).JoinAlias(() => user.Profiles, () => profile).
JoinAlias(() => user.OpenIdUsers, () => openIdUser).JoinAlias(() => user.UserType, () => userType)
.Where(() => user.UserName == claimedIdentifier)
.SelectList(l => l
.Select(x => openIdUser.OpenIdUserId).WithAlias(() => openIdUser.OpenIdUserId)
.Select(x => user.UserId).WithAlias(() => openIdUserDto.UserId)
.Select(x => openIdUser.OpenIdClaimedIdentifier).WithAlias(
() => openIdUserDto.ClaimedIdentifier)
.Select(x => openIdUser.OpenIdFriendlyIdentifier).WithAlias(
() => openIdUserDto.FriendlyIdentifier)
.Select(x => openIdUser.OpenIdEndPoint).WithAlias(
() => openIdUserDto.OpenIdEndPoint)
.Select(x => user.UserName).WithAlias(() => openIdUserDto.UserName)
.Select(x => userType.Type).WithAlias(() => openIdUserDto.UserType)
.Select(x => profile.DisplayName).WithAlias(() => openIdUserDto.DisplayName)
.Select(x => profile.EmailAddress).WithAlias(() => openIdUserDto.EmailAddress)
.Select(x => openIdUser.DateCreated).WithAlias(() => openIdUserDto.DateCreated)
.Select(x => openIdUser.LastUpdated).WithAlias(() => openIdUserDto.LastUpdated)
.Select(x => openIdUser.UsageCount).WithAlias(() => openIdUserDto.UsageCount)
).TransformUsing(Transformers.AliasToBean<OpenIdUserDto>()).Future<OpenIdUserDto>().Single();
}
This method sits in my UserRepository and is called by my UserService. Please not that this actually works, I just think it is overkill for such a simple task. Also please note that I am new to this so if this code is crappy I apologize in advance.
If you use Queryover then this is the only way.
If you really think less lines of code are preferable, more intuitive, or sits better with you then you can do either:-
Create a DB view and create mapings files for the view with
mutable="false" in your class definition and use protected set; on your class properties
Use the LINQ provider instead e.g. .Query (see
this blog post for more info)

How to do subqueries in nhibernate?

I need to do a subquery on a sub collection but I can't get it to work.
I tried this
Task tAlias = null;
List<Task> result = session.QueryOver<Task>(() => tAlias)
.Where(Restrictions.In(Projections.Property(() => tAlias.Course.Id), courseIds))
.WithSubquery.WhereExists(QueryOver.Of<CompletedTask>().Where(x => x.Student.StudentId == settings.StudentId))
().ToList();
Yet I get
Cannot use subqueries on a criteria
without a projection.
session.QueryOver<Task>(() => tAlias)
.WhereRestrictionsOn(x => x.Course.Id).IsIn(courseIds)
.WithSubquery.WhereExists(QueryOver.Of<CompletedTask>()
.Where(x => x.id == tAlias.id) //not sure how you need to link Task to CompletedTask
.Where(x => x.Student.StudentId == settings.StudentId)
.Select(x => x.id)) //exists requires some kind of projection (i.e. select clause)
.List<Task>();
or if you only want the completedtask then just...
Task taskAlias = null;
session.QueryOver<CompletedTask>()
.JoinAlias(x => x.Task, () => taskAlias)
.WhereRestrictionsOn(() => taskAlias.Course.Id).IsIn(courseIds)
.Where(x => x.Student.StudentId == settings.StudentId)
.List<CompletedTask>();
or look into setting up a student filter on the Task.CompletedTasks collection. I've never used this feature before. I believe you have to enable the filter and set the student parameter before you run the query. Then your Task object would only contain completedTasks by that student...
http://nhibernate.info/doc/nh/en/index.html#filters

Retrieving distinct values in mapping

I have an existing view which has too much data in it. Unfortunately I cannot get rid of it so I need to try to work around it using my NHibernate mapping. The idea is to have NH issue the following query:
SELECT DISTINCT User_Id, Module_Id, Application_Id, RightsMask
FROM V_UserApplicationPermissions
WHERE User_Id = ?
My current mapping for this list of AccessControlEntry types looks like this:
HasMany<AccessControlEntry>(x => x.Rights)
.WithTableName("V_UserApplicationPermissions")
.KeyColumnNames.Add("User_Id")
.Component(c =>
{
c.Map(x => x.Module, "Module_Id");
c.Map(x => x.Application, "App_Id");
c.Map(x => x.Rights, "RightsMask").CustomTypeIs<ApplicationRightsType>();
})
.Not.LazyLoad();
Any thoughts on how to have NHibernate put a DISTINCT keyword in there during the query?
UPDATE: Let me share the rest of the User map that might help as to why it isn't a straight forward criteria:
WithTable("Users");
Id(x => x.Id, "UserId");
Map(x => x.Name, "UserName");
HasMany<long>(x => x.Clients)
.WithTableName("V_UserClients")
.KeyColumnNames.Add("UserId")
.AsElement("ClientId");
Olivier Coanet from the NHUsers mailing list suggested hacking it into the WithTableName which worked:
HasMany<AccessControlEntry>(x => x.Rights)
.WithTableName("(SELECT DISTINCT User_Id, Module_Id, App_Id, RightsMask FROM V_UserApplicationPermissions)")
.KeyColumnNames.Add("User_Id")
.Component(c =>
{
c.Map(x => x.Module, "Module_Id");
c.Map(x => x.Application, "App_Id");
c.Map(x => x.Rights, "RightsMask").CustomTypeIs<ApplicationRightsType>();
})