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>();
})
Related
I may have possible mapped wrong, or something, NHibernate seems to be confusing to me, but when it works it is smooth. I have Google'd everything to this point and I am still learning NHibernate. I am trying to query an Address that has a accountId, which would link to my AccountUser map, which has a userId that would link to my Usermap. I want to look up all the addresses with the user name of "joe". Anyone know how I would do this with my query? below is my maps, and query:
public AddressMap()
{
Table("Address");
Id(x => x.Id).GeneratedBy.Native();
Map(x => x.FirstName);
Map(x => x.MiddleName);
Map(x => x.LastName);
Map(x => x.CompanyName);
Map(x => x.Street);
Map(x => x.City);
Map(x => x.State);
Map(x => x.AccountID);
Map(x => x.Name);
References(x => x.AccountUser);
}
public class AccountUserMap: ClassMap<AccountUser>
{
public AccountUserMap()
{
Table("AccountUser");
Id(x => x.Id).GeneratedBy.Native();
Map(x => x.UserId);
Map(x => x.AccountID).Not.Nullable();
References(x => x.User);
}
}
public UserMap()
{
Table("User");
Id(x => x.Id).GeneratedBy.Native();
Map(x => x.Name);
}
// non working query:
Address address = null;
User user = null;
AccountUser accountUser = null;
var query = session.QueryOver<Address>(() => address)
.JoinQueryOver(x => x.AccountUser, () => accountUser)
.Where(() => accountUser.AccountID == address.AccountID)
.JoinQueryOver(y => y.User, () => user)
.Where(() => user.Id == accountUser.UserId )
.And(() => user.Name == "joe")
.List()).ToList();
the error message isn't very helpful either...
{"Invalid column name 'AccountUser_id'.\r\nInvalid column name
'User_id'.\r\nInvalid column name 'AccountUser_id'.\r\nInvalid column
name 'User_id'."}
there is nothing named with the underscore, so it must be something with NHibernate
Also, this SQL query below works, and is what I want to do:
SELECT TOP 1000
[AddressID]
,[FirstName]
,[MiddleName]
,[LastName]
FROM Address
inner join AccountUser accountUser
on AccountUser.AccountID = Address.AccountID
inner join User user
on user.UserID = accountUser.UserID
where user.Name= 'joe'
Hopefully thats enough detail
If the property names do not match the database names you have to specify them in the mapping, for example:
Id(x => x.Id, "AddressID").GeneratedBy.Native();
or Fluent NHibernate will use its default naming convention for key columns.
I am trying to project a single value from an entity's association with no luck. Only want the city name from the TrainerAddress in the query below. Trainer address is mapped as a component of Trainer.
session.QueryOver<Trainer>()
.JoinAlias(x=>x.TrainerAddress.City, ()=> cityAlias, JoinType.LeftOuterJoin)
.OrderBy(x => x.Name).Asc
.SelectList(list => list
.Select(x => x.Id).WithAlias(() => dto.Id)
.Select(x => x.Name).WithAlias(() => dto.Name)
.Select(x => x.TrainerAddress.City.Name).WithAlias(() => dto.City))//issue projecting here
.TransformUsing(Transformers.AliasToBean<TrainerDTO>())
.List<TrainerDTO>();
Is this possible?
You're specifying an alias for TrainerAddress.City but you don't use that alias anywhere?
I'm not 100% sure if NHibernate supports components well in QueryOver, I know there were some issues with it using Criteria, but maybe this will work:
session.QueryOver<Trainer>()
.JoinAlias(x=> x.TrainerAddress.City, ()=> cityAlias, JoinType.LeftOuterJoin)
.OrderBy(x => x.Name).Asc
.SelectList(list => list
.Select(x => x.Id).WithAlias(() => dto.Id)
.Select(x => x.Name).WithAlias(() => dto.Name)
.Select(x => cityAlias.Name).WithAlias(() => dto.City))
.TransformUsing(Transformers.AliasToBean<TrainerDTO>())
.List<TrainerDTO>();
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);
I want to specify the class map for 1 of the elements in composite id:
CompositeId()
.KeyReference(x => x.User, "user_id")
.KeyProperty(x => x.Key, "user_key");
Like this one:
References(x => x.User, "user_id").Class<User>()
But I get error for unmapped class because I use interfaces. I also tried the code bellow but no luck yet:
CompositeId()
.KeyReference(x => x.User, e =>
e.Name(""user_id").EntityName("User"))
.KeyProperty(x => x.Key, "user_key");
References(x => x.User, "user_id").Class<User>()
this is the answer:
https://groups.google.com/forum/#!topic/fluent-nhibernate/AnJosrxqIo8
I have a 'User' Entity that contains an 'Address' Value Object. I have this mapping ok using FNH's Component concept. However, the Address VO also contains a Country which is another value object. I had assumed that this should be just nested as another component, but this doesn't seem to work. Can anyone tell me how I should solve this?
Code for mapping is below...
Thanks!
public UserMapping()
{
Table("Users");
Id(c => c.Id).GeneratedBy.HiLo("100");
Map(c => c.UserName).Not.Nullable().Length(64);
Map(c => c.Email).Not.Nullable().Length(128);
Map(c => c.Password).Not.Nullable().Length(256);
Map(c => c.Roles).Length(64);
Map(c => c.FirstName).Not.Nullable().Length(64);
Map(c => c.LastName).Not.Nullable().Length(64);
Map(c => c.BirthDate).Not.Nullable();
//Address
Component(x => x.Address, m =>
{
m.Map(x => x.AddressLine1).Not.Nullable();
m.Map(x => x.AddressLine2);
m.Map(x => x.City).Not.Nullable();
m.Map(x => x.Region);
m.Map(x => x.PostalCode).Not.Nullable();
//*****Country Here********
// country has Name and Code
});
}
Ah, Jimmy Bogard from the FNH mailing list showed me - it's quite straightforward. I don't know what I was doing before! Anyway, for anyone else who's interested:
Component(c => c.Address, m =>
{
m.Component(cp => cp.Country, m2 =>
{
m2.Map(x => x.Name); //etc
}
I would create a map for Country and use m.References(x => x.Country).