NHibernate QueryOver with SelectList - c#

I have multiple queries against one table. As not all columns/properties are needed I specify the columns with the help of select list. Take the following method as example. This method is working
public IEnumerable<ResultDto> GetEntityAsDto(eStatusBinderProduktion fromState, eStatusBinderProduktion toState)
{
EntityClass entityAlias = null;
ResultDto resultAlias = null;
var query = Session.QueryOver<EntityClass>(() => entityAlias)
.Where(() => entityAlias.ProduktionStatus >= (byte)fromState)
.And(() => entityAlias.ProduktionStatus <= (byte)toState);
query.SelectList(list => list
.Select(() => entityAlias.PrimaryID).WithAlias(() => resultAlias.PrimaryID)
.Select(() => entityAlias.SecondaryID).WithAlias(() => resultAlias.SecondaryID)
);
return query.TransformUsing(Transformers.AliasToBean<ResultDto>())
.List<ResultDto>();
}
As I need to define the SelectList in multiple methods, I tried to to move the SelectList into a separate method.
The following code is not working, NHibernate throws the exception
NHibernate.QueryException: 'could not resolve property: entity.PrimaryID of: MyProjectNamespace.DAL.Interfaces.Entities.EntityClass'
"
public IEnumerable<ResultDto> GetEntityAsDto(eStatusBinderProduktion fromState, eStatusBinderProduktion toState)
{
EntityClass entityAlias = null;
ResultDto resultAlias = null;
var query = Session.QueryOver<EntityClass>(() => entityAlias)
.Where(() => entityAlias.ProduktionStatus >= (byte)fromState)
.And(() => entityAlias.ProduktionStatus <= (byte)toState);
MapPropertiesOfEntityToResult(entityAlias, resultAlias, query);
return query.TransformUsing(Transformers.AliasToBean<ResultDto>())
.List<ResultDto>();
}
private void MapPropertiesOfEntityToResult(EntityClass entity, ResultDto resultAlias, IQueryOver<EntityClass, EntityClass> query)
{
query.SelectList(list => list
.Select(() => entity.PrimaryID).WithAlias(() => resultAlias.PrimaryID)
.Select(() => entity.SecondaryID).WithAlias(() => resultAlias.SecondaryID)
);
}
Additional information:
- The mappings are correct
- table is filled with test data

We do not need alias for filling SelectList. We can profit from the Type parameters coming with IQueryOver<TRoot,TSubType>:
//private void MapPropertiesOfEntityToResult(EntityClass entity
// , ResultDto resultAlias, IQueryOver<EntityClass, EntityClass> query)
private void MapPropertiesOfEntityToResult( // no need for entity
ResultDto resultAlias, IQueryOver<EntityClass, EntityClass> query)
{
query.SelectList(list => list
//.Select(() => entity.PrimaryID).WithAlias(() => resultAlias.PrimaryID)
//.Select(() => entity.SecondaryID).WithAlias(() => resultAlias.SecondaryID)
.Select(entity => entity.PrimaryID).WithAlias(() => resultAlias.PrimaryID)
.Select(entity => entity.SecondaryID).WithAlias(() => resultAlias.SecondaryID)
);
}
The entity is now a parameter of the passed Function and its type is coming from IQueryOver definition

Related

how multiple map in automapper

I recently met with an automapper. I have a question, how i can map multiple objects from my repostiory in one DTO.
public QuestionProfile()
{
CreateMap<Question, GrammarQuestionDTO>()
.ForMember(g => g.Question, q => q.MapFrom(source => source.Text)).ReverseMap();
CreateMap<List<GrammarQuestionDTO>, TestDTO>()
.ForMember(t => t.GrammarQuestion, g => g.MapFrom(source => source)).ReverseMap();
CreateMap<Question, AuditionQuestionDTO>()
.ForMember(a => a.Question, q => q.MapFrom(source => source.Text))
.ForMember(a => a.Url, q => q.MapFrom(source => source.AudioFile.Url)).ReverseMap();
CreateMap<List<AuditionQuestionDTO>, TestDTO>()
.ForMember(t => t.AuditionQuestion, a => a.MapFrom(source => source)).ReverseMap();
}
how can I map all these 4 objects?
public async Task<TestDTO> GenerateTest(LevelType level)
{
var grammarQuestions = await _questionRepository.GetGrammarQuestionAsync(level);
var auditionQuestions = await _questionRepository.GetAuditionQuestionAsync(level);
var essayTopic = await _questionRepository.GetEssayTopicAsync(level);
var speakingTopic = await _questionRepository.GetSpeakingTopicAsync(level);
var test = _mapper.Map<TestDTO>(grammarQuestions);
test = _mapper.Map(test, auditionQuestions); //there will be a conversion error
return _mapper.Map<TestDTO>(grammarQuestions);
}
You need to map it without list, just map it one to one and AutoMapper will handle the collections:
CreateMap<AuditionQuestionDTO, TestDTO>()
.ForMember(t => t.AuditionQuestion,
a => a.MapFrom(source => source.<PropertyName>)).ReverseMap();
And then on the map you should:
test = _mapper.Map<List<AuditionQuestionDTO>>(test, auditionQuestions);

EntityFramework - .Select() Projection with anonymous object throws a Exception that I am not sure how to interpret [duplicate]

This question already has an answer here:
The Include path expression must refer to a navigation property defined on the type.in eager loading
(1 answer)
Closed 3 years ago.
Exception
The Include path expression must refer to a navigation property defined on the type. Use dotted paths for reference navigation properties and the Select operator for collection navigation properties.
This is the call causing this. Vignette is a Collection, so in my opinion this statement should be valid.
public ICollection<CarSharingEntry> GetAllCarSharingEntriesByUserSAM(string userSAM)
{
try
{
using (var _dbContext = new CarSharingContext())
{
_dbContext.Configuration.LazyLoadingEnabled = false;
return _dbContext.CarSharingEntries
.Include(e => e.ShareMeeting)
.Include(e => e.SelectedOptions)
.Include(e => e.SharedCar)
// Code Block causing this v
.Include(e => e.SharedCar.Vignette
.Select(v => new
{
v.Id,
v.GUID,
v.CountryName,
v.CountryCode
})
)
// ---------------------------
.Include(e => e.SharedCar.VehicleType)
.Include(e => e.SharedCar.Equipment)
.Include(e => e.SharedCar.FuelType)
.Include(e => e.SharedCar.Location)
.Include(e => e.CarSharer.Select(c => c.ContactDetails))
.Where(e => e.SharedCar.isForCarSharing)
// Commented out for debugging
//.Where(e => e.CarSharer.Any(p => p.SAM == userSAM))
.ToList();
}
}
catch (Exception ex)
{
throw ex;
}
}
What am I missing here?
You cannot include a select with an anonymous type:
.Include(e => e.SharedCar.Vignette
.Select(v => new
{
v.Id,
v.GUID,
v.CountryName,
v.CountryCode
})
)
Instead, include the related object directly:
.Include(e => e.SharedCar.Select(s => s.Vignette))
If you wish to only get some of the values from Vignette, you could do this by adding a .Select(x => new CarSharingEntry { ... }) and specifying what you want to do with each item before the ToList()
.Select(e => new CarSharingEntry {
ShareMeeting = e.ShareMeeting,
SelectedOptions = e.SelectedOptions,
SharedCar = new SharedCar {
Vignette = e.SharedCar.Vignette.Select(v => new {
v.Id,
v.GUID,
v.CountryName,
v.CountryCode
}),
VehicleType = e.SharedCar.VehicleType,
Equipment = e.SharedCar.Equipment,
// etc, etc...
},
}).ToList()

How to use datediff sql function in nHibernate?

I am developing an application to test execution time SQL queries using different frameworks. I have some problem to write one of the queries using Fluent nHibernate. The query should return all employees that are older than 50 years. In some page I found the DateProjections class which I attach below.
public static class DateProjections
{
private const string DateDiffFormat = "datediff({0}, ?1, ?2)";
public static IProjection DateDiff(
string datepart,
Expression<Func<object>> startDate,
Expression<Func<object>> endDate)
{
// Build the function template based on the date part.
string functionTemplate = string.Format(DateDiffFormat, datepart);
return Projections.SqlFunction(
new SQLFunctionTemplate(NHibernateUtil.Int32, functionTemplate),
NHibernateUtil.Int32,
Projections.Property(startDate),
Projections.Property(endDate));
}
}
The function to get employees is the following:
public List<EmployeeAgeViewModel> GetEmployeesOlderThan50()
{
Person personAlias = null;
EmployeeAgeViewModel result = null;
var temp = _session.QueryOver<Employee>().JoinQueryOver(x => x.Person, () => personAlias).SelectList(
list => list
.Select(x => personAlias.FirstName).WithAlias(() => result.FirstName)
.Select(x => personAlias.LastName).WithAlias(() => result.LastName)
.Select(x => x.Gender).WithAlias(() => result.Gender)
.Select(x => x.BirthDate).WithAlias(() => result.BirthDate)
.Select(x => x.HireDate).WithAlias(() => result.HireDate)
.Select(DateProjections.DateDiff("yy", () => personAlias.Employee.BirthDate, () => DateTime.Now)).WithAlias(() => result.Age)
)
.TransformUsing(Transformers.AliasToBean<EmployeeAgeViewModel>())
.List<EmployeeAgeViewModel>();
return temp.ToList();
The problem is probably the way I am passing BirthDate property and DateTime.Now to DateDiff function. In the personAlias variable the Employee property is null - maybe I should assign it somehow before - any help will be appreciated.
Instead of personAlias.Employee.BirthDate you need to use an employeeAlias.
Your code with the necessary changes looks like this:
Person personAlias = null;
Employee employeeAlias = null;
EmployeeAgeViewModel result = null;
var temp = _session.QueryOver<Employee>(() => employeeAlias)
.JoinQueryOver(x => x.Person, () => personAlias)
.SelectList(
list => list
.Select(x => personAlias.FirstName).WithAlias(() => result.FirstName)
.Select(x => personAlias.LastName).WithAlias(() => result.LastName)
.Select(x => x.Gender).WithAlias(() => result.Gender)
.Select(x => x.BirthDate).WithAlias(() => result.BirthDate)
.Select(x => x.HireDate).WithAlias(() => result.HireDate)
.Select(DateProjections.DateDiff("yy", () => employeeAlias.BirthDate, () => DateTime.Now))
.WithAlias(() => result.Age)
)
.TransformUsing(Transformers.AliasToBean<EmployeeAgeViewModel>())
.List<EmployeeAgeViewModel>();
return temp.ToList();

Cannot convert IQueryable<IEnumerable<string>> to return type IEnumerable<string>

In the following function I get an error when I try to return a value saying:
Cannot convert
System.Linq.IQueryable<System.Collections.Generic.IEnumerable<string>>
to return type System.Collections.Generic.IEnumerable<string>
public IEnumerable<string> GetModuleKindPropertyNames(long moduleKindId)
{
var configurationId = GetModuleKindPertypeConfigurationId(moduleKindId);
var propertyNames = _dbSis.ModuleKinds
.Where(t => t.PerTypeConfigurationId == configurationId)
.Select(x => x.PerTypeConfiguration.Properties
.Select(z => z.Name));
return propertyNames; //red line below property names
}
How can I solve this issue?
It looks like you want to select items from a collection within a collection and flatten the result into a single sequence.
Conceptually, something like:
If that's the case, you're looking for the SelectMany method:
var propertyNames = _dbSis.ModuleKinds
.Where(t => t.PerTypeConfigurationId == configurationId)
.SelectMany(x => x.PerTypeConfiguration.Properties)
.Select(z => z.Name);

Get NHibernate QueryOver .SelectList(x) from Function

Is there a way to get a list of members from a function that can be passed in to SelectList()?
So instead of doing this
var dtos = repository.QueryOver<MicrofilmExportProcessed>()
.SelectList(list => list
.Select(x => x.Member1).WithAlias(() => dto.Member1)
.Select(x => x.Member2).WithAlias(() => dto.Member2)
.Select(x => x.Member3).WithAlias(() => dto.Member3))
.List<MicrofilmExportProcessed>();
Doing something like this:
var dtos = repository.QueryOver<MicrofilmExportProcessed>()
.SelectList(getMembersFromFunc())
.List<MicrofilmExportProcessed>();
I tried creating method that returns the same type as the input parameter of the SelectList but it still tells me the input type is invalid. Not sure what I'm missing.
Something like
Func<QueryOverProjectionBuilder<InvoiceDto>, QueryOverProjectionBuilder<InvoiceDto>> GetList()
{
InvoiceDto dto = null;
return list => list.Select(w => w.Client).WithAlias(() => dto.Client);
}
and call it like
return Session.QueryOver<InvoiceDto>()
.SelectList(GetList())
.TransformUsing(Transformers.AliasToBean<InvoiceDto>())
.List<InvoiceDto>();

Categories