NHibernate Projections - How to project a value from within associations - nhibernate

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>();

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();

How to project value object (component) into a DTO?

Is it possible to transform component into a dto when creating projections via SelectList.
I have a value object Name, and I need to project it into a Dto NameInfo. Below is the query.
I need a step here on this line
.Select(c=> coveredInsured.Name).WithAlias(()=>info.Name)
something along the lines
.Select(c => new NameInfo { Last= c.Last, First=c.First, Middle = c.Middle}).WithAlias(()=>info.Name)
This is the actual query that fails becuase it cannot convert Name into NameInfo. So. other then exposing three properties on my dto, is there a way to project?
.SelectList(list => list
.Select(c => c.Id).WithAlias(() => info.CoverageId)
.Select(c => bid.Year).WithAlias(() => info.PolicyYear)
.Select(c => bid.OptionNumber).WithAlias(() => info.OptionNumber)
.Select(c=> ((ClientBase)client).Number).WithAlias(()=>info.ClientNumber)
.Select(c => c.PrimaryInsured.Id).WithAlias(() => info.PrimaryInsuredId)
.Select(c => c.CoveredInsured.Id).WithAlias(() => info.CoveredInsuredId)
.Select(c=> coveredInsured.Name).WithAlias(()=>info.Name)
)
.TransformUsing(Transformers.AliasToBean<InsuredCoverageInfo>())
.List<InsuredCoverageInfo>()
.ToList();

NHibernate projection: How to create AliasToBean projection?

I am trying to convert this inefficient query into one that projects into a dto.
Original query looks like this:
var flatFeePolicies = _session.QueryOver<FlatChargeAccessFee>(() => flatChargeAccessFeeAlias)
.JoinAlias(x => x.AgreementAccessFee, () => agreementAccessFeeAlias)
.JoinQueryOver(x => x.ClientPolicy, () => clientPolicyAlias)
.Where(y => agreementAccessFeeAlias.Agreement.Id == request.AgreementId)
.List()
.Select(x => new FlatChargeAccessFeeInfo()
{
FlatChargeAccessFeeId = x.Id,
ClientName = x.ClientPolicy.Bid.Client.Name,
PolicyNumber = x.ClientPolicy.PolicyNumber,
ClientPolicyId = x.ClientPolicy.Id,
AgreementAccessFeeId = x.AgreementAccessFee.Id,
ShouldCheckBeGenerated = x.ShouldCheckBeGenerated,
MonthlyFee = x.MontlyFeeAmount.Amount.ToString(),
PolicyYear = x.ClientPolicy.PolicyNumber.Year
})
.ToList();
I tried it like this:
var flatFeePolicies = _session.QueryOver<FlatChargeAccessFee>(() => flatChargeAccessFeeAlias)
.JoinAlias(x => x.AgreementAccessFee, () => agreementAccessFeeAlias)
.JoinQueryOver(x => x.ClientPolicy, () => clientPolicyAlias)
.Where(y => agreementAccessFeeAlias.Agreement.Id == request.AgreementId)
.SelectList(list => list
.Select(x => x.Id).WithAlias(() => feeInfo.FlatChargeAccessFeeId)
.Select(x => x.ClientPolicy.Bid.Client.Name).WithAlias(() => feeInfo.ClientName)
.Select(x => x.ClientPolicy.PolicyNumber).WithAlias(() => feeInfo.PolicyNumber)
.Select(x => x.ClientPolicy.Id).WithAlias(() => feeInfo.ClientPolicyId)
.Select(x => x.AgreementAccessFee.Id).WithAlias(() => feeInfo.AgreementAccessFeeId)
.Select(x => x.ShouldCheckBeGenerated).WithAlias(() => feeInfo.ShouldCheckBeGenerated)
.Select(x => x.MontlyFeeAmount.Amount.ToString()).WithAlias(() => feeInfo.MonthlyFee)
.Select(x => x.ClientPolicy.PolicyNumber.Year).WithAlias(() => feeInfo.PolicyYear)
)
.TransformUsing(Transformers.AliasToBean<FlatChargeAccessFeeInfo>())
.List<FlatChargeAccessFeeInfo>();
and I am getting an error that variable "x" has been referenced in scope but was not defined. What is the proper syntax to convert this?
After help from Andrew, here is the correct version that works
ClientPolicy clientPolicyAlias = null;
Client clientAlias = null;
Bid bidAlias = null;
AgreementAccessFee agreementAccessFeeAlias = null;
FlatChargeAccessFee flatChargeAccessFeeAlias = null;
FlatChargeAccessFeeInfo feeInfo = null;
var flatFeePolicies = _session.QueryOver<FlatChargeAccessFee>(() => flatChargeAccessFeeAlias)
.JoinAlias(a => a.AgreementAccessFee, () => agreementAccessFeeAlias)
.JoinQueryOver(b => b.ClientPolicy, () => clientPolicyAlias)
.JoinAlias(b=>b.Bid,()=>bidAlias)
.JoinAlias(b=>b.Client, ()=>clientAlias)
.Where(c => agreementAccessFeeAlias.Agreement.Id == request.AgreementId)
.SelectList(list => list
.Select(d => d.Id).WithAlias(() => feeInfo.FlatChargeAccessFeeId)
.Select(e => clientAlias.Name).WithAlias(() => feeInfo.ClientName)
.Select(e => clientAlias.Number).WithAlias(() => feeInfo.ClientNumber)
.Select(f => bidAlias.OptionNumber).WithAlias(() => feeInfo.BidOptionNumber)
.Select(f => bidAlias.Year).WithAlias(()=>feeInfo.PolicyYear)
.Select(g => clientPolicyAlias.Id).WithAlias(() => feeInfo.ClientPolicyId)
.Select(h => agreementAccessFeeAlias.Id).WithAlias(() => feeInfo.AgreementAccessFeeId)
.Select(j => j.ShouldCheckBeGenerated).WithAlias(() => feeInfo.ShouldCheckBeGenerated)
.Select(k => k.MontlyFeeAmount.Amount).WithAlias(()=>feeInfo.MonthlyFee)
)
.TransformUsing(Transformers.AliasToBean<FlatChargeAccessFeeInfo>())
.List<FlatChargeAccessFeeInfo>();
You're close, a few things though:
This select:
.Select(x => x.MontlyFeeAmount.Amount.ToString()).WithAlias(() => feeInfo.MonthlyFee)
will not work. QueryOver attempts to turn your code directly into SQL. If the property does not exist as a column in the database, the query won't work properly (unless you're using a mapped custom type, QueryOver can handle those)
Nested property access won't work either:
.Select(x => x.ClientPolicy.Bid.Client.Name).WithAlias(() => feeInfo.ClientName)
for a similar reason listed above. QueryOver will attempt to turn your property access directly into SQL. You'll need to explicitly join from ClientPolicy to Bid to Client.
In general, remember that you're writing code that's going to be turned into SQL. In fact, I normally write the SQL I want to generate first and then write the QueryOver that corresponds to that. Hope that helps!

NHibernate fetch with transformation

im trying to query using QueryOver and im trying to do some transformation with fetching.
But im hitting error
HSPTransactionDto hspTransactionDto = null;
var hspTransactionDtoList =
Session.QueryOver<Transaction>()
.Where(x => x.TransactionStatus == TransactionStatus.Draft)
.Fetch(x => x.HealthServiceProvider).Eager
.Fetch(x => x.HealthMaintenanceOrganization).Eager
.SelectList(list => list
.Select(x => x.Id).WithAlias(() => hspTransactionDto.Id)
.Select(x => x.Version).WithAlias(() => hspTransactionDto.Version)
.Select(x => x.HealthServiceProvider.Id).WithAlias(() => hspTransactionDto.HSPId)
.Select(x => x.HealthServiceProvider.Name).WithAlias(() => hspTransactionDto.HSPName)
.Select(x => x.HealthMaintenanceOrganization.Id).WithAlias(() => hspTransactionDto.HMOId)
.Select(x => x.HealthMaintenanceOrganization.Name).WithAlias(() => hspTransactionDto.HMOName)
.Select(x => x.HSPPatientCode).WithAlias(() => hspTransactionDto.HSPPatientCode)
.Select(x => x.PatientFirstName).WithAlias(() => hspTransactionDto.PatientFirstName)
.Select(x => x.PatientMiddleName).WithAlias(() => hspTransactionDto.PatientMiddleName)
.Select(x => x.PatientLastName).WithAlias(() => hspTransactionDto.PatientLastName)
)
.TransformUsing(Transformers.AliasToBean<HSPTransactionDto>()).List<HSPTransactionDto>();
return hspTransactionDtoList;
anyone can help?
actually found the answer just need to put some alias so i ended up with
HSPTransactionDto hspTransactionDto = null;
HealthMaintenanceOrganization hmoAlias = null;
HealthServiceProvider hspAlias = null;
var hspTransactionDtoList =
Session.QueryOver<Transaction>()
.Where(a => a.TransactionStatus == TransactionStatus.Draft)
.Fetch(b => b.HealthServiceProvider).Eager
.Fetch(c => c.HealthMaintenanceOrganization).Eager
.JoinAlias(x=> x.HealthMaintenanceOrganization,() => hmoAlias)
.JoinAlias(x => x.HealthServiceProvider, () => hspAlias)
.SelectList(list => list
.Select(x => x.Id).WithAlias(() => hspTransactionDto.Id)
.Select(x => x.Version).WithAlias(() => hspTransactionDto.Version)
.Select(x => hspAlias.Id).WithAlias(() => hspTransactionDto.HSPId)
.Select(x => hspAlias.Name).WithAlias(() => hspTransactionDto.HSPName)
.Select(x => hmoAlias.Id).WithAlias(() => hspTransactionDto.HMOId)
.Select(x => hmoAlias.Name).WithAlias(() => hspTransactionDto.HMOName)
.Select(x => x.HSPPatientCode).WithAlias(() => hspTransactionDto.HSPPatientCode)
.Select(x => x.PatientFirstName).WithAlias(() => hspTransactionDto.PatientFirstName)
.Select(x => x.PatientMiddleName).WithAlias(() => hspTransactionDto.PatientMiddleName)
.Select(x => x.PatientLastName).WithAlias(() => hspTransactionDto.PatientLastName)
)
.TransformUsing(Transformers.AliasToBean<HSPTransactionDto>()).List<HSPTransactionDto>();
return hspTransactionDtoList;
anyone know a cleaner way?
I think you don't need to use Fetch, because you've used Select for selective properties and it's grouped with DTO:
HSPTransactionDto hspTransactionDto = null;
HealthMaintenanceOrganization hmoAlias = null;
HealthServiceProvider hspAlias = null;
var hspTransactionDtoList =
Session.QueryOver<Transaction>()
.Where(a => a.TransactionStatus == TransactionStatus.Draft)
.JoinAlias(x=> x.HealthMaintenanceOrganization,() => hmoAlias)
.JoinAlias(x => x.HealthServiceProvider, () => hspAlias)
.SelectList(list => list
.Select(x => x.Id).WithAlias(() => hspTransactionDto.Id)
.Select(x => x.Version).WithAlias(() => hspTransactionDto.Version)
.Select(x => hspAlias.Id).WithAlias(() => hspTransactionDto.HSPId)
.Select(x => hspAlias.Name).WithAlias(() => hspTransactionDto.HSPName)
.Select(x => hmoAlias.Id).WithAlias(() => hspTransactionDto.HMOId)
.Select(x => hmoAlias.Name).WithAlias(() => hspTransactionDto.HMOName)
.Select(x => x.HSPPatientCode).WithAlias(() => hspTransactionDto.HSPPatientCode)
.Select(x => x.PatientFirstName).WithAlias(() => hspTransactionDto.PatientFirstName)
.Select(x => x.PatientMiddleName).WithAlias(() => hspTransactionDto.PatientMiddleName)
.Select(x => x.PatientLastName).WithAlias(() => hspTransactionDto.PatientLastName)
)
.TransformUsing(Transformers.AliasToBean<HSPTransactionDto>()).List<HSPTransactionDto>();
return hspTransactionDtoList;

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)