- Home
- LLBLGen Pro
- LLBLGen Pro Runtime Framework
Automapping Linq queries
Joined: 26-Aug-2006
Hello,
i'm jumping on the Model bandwagon and there is something in particular I am trying to achieve. I'd to be to leverage AutoMapper within my linq query.
For example I'd like to change this bit of code:
public IQueryable<InstituteFollowUp> FindPendingFollowUps(int assigneeId)
{
LinqMetaData meta = new LinqMetaData(Adapter);
var followUps = from c in meta.InstituteFollowUp
where c.IsComplete == false && c.FollowUpAssigneeId == assigneeId
select new InstituteFollowUp()
{
InstituteId = c.InstituteUsingInstituteId.Id,
Institute = c.InstituteUsingInstituteId.Name,
Note = c.Note,
FollowUpDate = c.FollowUpDate,
FollowUpId = c.Id
};
return followUps;
}
to (something close to)
public IQueryable<InstituteFollowUp> FindPendingFollowUps(int assigneeId)
{
LinqMetaData meta = new LinqMetaData(Adapter);
var followUps = from c in meta.InstituteFollowUp
where c.IsComplete == false && c.FollowUpAssigneeId == assigneeId
select AutoMapper.Mapper.Map<IAEC.SMS.Core.EntityClasses.InstituteFollowUpEntity, InstituteFollowUp>(c);
return followUps;
}
There being a number of benefits to this. It's brevity and it allows me to not have to keep defining how an entity is mapped to my model. Also, I would assume it would only select the columns that are mapped.
Heres the mapping:
AutoMapper.Mapper.CreateMap<IAEC.SMS.Core.EntityClasses.InstituteFollowUpEntity, InstituteFollowUp>().ForMember(
p => p.FollowUpId, p => p.MapFrom(x => x.Id));
But that doesn't work, I get an error saying that XEntity cannot be cast to System.Int32. Which is a bit odd... Is there a way to make this work?
I'm using llbl 2.6.
Stacktrace:
[InvalidCastException: Unable to cast object of type 'System.Int32' to type 'IAEC.SMS.Core.EntityClasses.InstituteFollowUpEntity'.] lambda_method(ExecutionScope , Object[] , Int32[] ) +50 SD.LLBLGen.Pro.LinqSupportClasses.DataProjectorToObjectList
1.AddRowToResults(IList projectors, Object[] rawProjectionResult) +104 SD.LLBLGen.Pro.LinqSupportClasses.DataProjectorToObjectList
1.SD.LLBLGen.Pro.ORMSupportClasses.IGeneralDataProjector.AddProjectionResultToContainer(List1 valueProjectors, Object[] rawProjectionResult) +9 SD.LLBLGen.Pro.ORMSupportClasses.ProjectionUtils.FetchProjectionFromReader(List
1 valueProjectors, IGeneralDataProjector projector, IDataReader datasource, Int32 maxNumberOfItemsToReturn, Int32 pageNumber, Int32 pageSize, Boolean clientSideLimitation, Boolean clientSideDistinctFiltering, Boolean clientSidePaging, UniqueList1 stringCache, Dictionary
2 typeConvertersToRun) +1221 SD.LLBLGen.Pro.ORMSupportClasses.DataAccessAdapterBase.FetchProjection(List1 valueProjectors, IGeneralDataProjector projector, IRetrievalQuery queryToExecute, Dictionary
2 typeConvertersToRun) +132 SD.LLBLGen.Pro.ORMSupportClasses.DataAccessAdapterBase.FetchProjection(List1 valueProjectors, IGeneralDataProjector projector, IEntityFields2 fields, IRelationPredicateBucket filter, Int32 maxNumberOfItemsToReturn, ISortExpression sortClauses, IGroupByCollection groupByClause, Boolean allowDuplicates, Int32 pageNumber, Int32 pageSize) +245 SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProProvider2.ExecuteValueListProjection(QueryExpression toExecute) +312 SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProProviderBase.ExecuteExpression(Expression handledExpression) +183 SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProProviderBase.Execute(Expression expression) +23 SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProProviderBase.System.Linq.IQueryProvider.Execute(Expression expression) +17 SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProQuery
1.Execute() +16 SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProQuery1.System.Collections.Generic.IEnumerable<T>.GetEnumerator() +16 System.Linq.Buffer
1..ctor(IEnumerable1 source) +247 System.Linq.<GetEnumerator>d__0.MoveNext() +108 System.Web.Script.Serialization.JavaScriptSerializer.SerializeEnumerable(IEnumerable enumerable, StringBuilder sb, Int32 depth, Hashtable objectsInUse, SerializationFormat serializationFormat) +76 System.Web.Script.Serialization.JavaScriptSerializer.SerializeValueInternal(Object o, StringBuilder sb, Int32 depth, Hashtable objectsInUse, SerializationFormat serializationFormat) +1294 System.Web.Script.Serialization.JavaScriptSerializer.SerializeValue(Object o, StringBuilder sb, Int32 depth, Hashtable objectsInUse, SerializationFormat serializationFormat) +175 System.Web.Script.Serialization.JavaScriptSerializer.SerializeCustomObject(Object o, StringBuilder sb, Int32 depth, Hashtable objectsInUse, SerializationFormat serializationFormat) +566 System.Web.Script.Serialization.JavaScriptSerializer.SerializeValueInternal(Object o, StringBuilder sb, Int32 depth, Hashtable objectsInUse, SerializationFormat serializationFormat) +1338 System.Web.Script.Serialization.JavaScriptSerializer.SerializeValue(Object o, StringBuilder sb, Int32 depth, Hashtable objectsInUse, SerializationFormat serializationFormat) +175 System.Web.Script.Serialization.JavaScriptSerializer.Serialize(Object obj, StringBuilder output, SerializationFormat serializationFormat) +24 System.Web.Script.Serialization.JavaScriptSerializer.Serialize(Object obj, SerializationFormat serializationFormat) +74 System.Web.Script.Serialization.JavaScriptSerializer.Serialize(Object obj) +6 System.Web.Mvc.JsonResult.ExecuteResult(ControllerContext context) +254 System.Web.Mvc.ControllerActionInvoker.InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult) +10 System.Web.Mvc.<>c__DisplayClass11.<InvokeActionResultWithFilters>b__e() +20 System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func
1 continuation) +251 System.Web.Mvc.<>c__DisplayClass13.<InvokeActionResultWithFilters>b__10() +19 System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func1 continuation) +251 System.Web.Mvc.<>c__DisplayClass13.<InvokeActionResultWithFilters>b__10() +19 System.Web.Mvc.ControllerActionInvoker.InvokeActionResultWithFilters(ControllerContext controllerContext, IList
1 filters, ActionResult actionResult) +178 System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) +399 System.Web.Mvc.Controller.ExecuteCore() +126 System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext) +27 System.Web.Mvc.ControllerBase.System.Web.Mvc.IController.Execute(RequestContext requestContext) +7 System.Web.Mvc.MvcHandler.ProcessRequest(HttpContextBase httpContext) +151 System.Web.Mvc.MvcHandler.ProcessRequest(HttpContext httpContext) +57 System.Web.Mvc.MvcHandler.System.Web.IHttpHandler.ProcessRequest(HttpContext httpContext) +7 System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +181 System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +75
Joined: 17-Aug-2003
The problem is that the linq provider doesn't support a projection to a class type (anonymous or custom) which receives an entity typed variable, because the entity instance you pass to the element you return isn't instantiated and won't be instantiated as well.
This is something we hope to fix in v3.0 (it's on the list of issues to fix before RTM), but it's likely a difficult task as our framework uses 2 paths to fetch data: one for entity instances and one for all other projections. This is because entity projections support inheritance and custom projections are as-is.
You run into this particular scenario. It's the same as: var q = from c in metadata.Customer select new { Entity = c};
Joined: 06-Sep-2012
Otis wrote:
What have you tried? You can return entities in a custom projection now
i tried couple of things and both didn't work. not sure what you mean by custom projection..sorry
This is the first bit i tried
Dim metaData As New LinqMetaData
Dim q = From p In metaData.TblCostCentre _
Select p
Mapper.CreateMap(Of SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProQuery(Of CostCentre), EntityClasses.TblCostCentreEntity)()
Mapper.Map(Of SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProQuery(Of CostCentre), EntityClasses.TblCostCentreEntity)(q)
Return q
This is the second bit i tried
Public Function GetAllCostCentres() As IQueryable(Of Model.CostCentre) Implements ICostCentreRepository.GetAllCostCentres
Mapper.CreateMap(Of TblCostCentreEntity, CostCentre)()
Dim metaData As New LinqMetaData
Dim q = From p In metaData.TblCostCentre _
Select Mapper.Map(Of IQueryable(Of CostCentre), TblCostCentreEntity)(p)
'Dim t As IQueryable(Of CostCentre) = Mapper.Map(Of CostCentre)(q)
'Select New CostCentre With {.Active = p.Active, .CostCentre = p.CostCentre, .CreatedBy = p.CreatedBy, .DateCreated = p.DateCreated, .DateLastModified = p.DateLastModified, .ModifiedBy = p.ModifiedBy, .CostCentreID = p.CostCentreId}
Return q
End Function
The last one throws me this error
Unable to cast object of type 'SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProQuery1[Mail.DAL.EntityClasses.TblCostCentreEntity]' to type 'System.Linq.IQueryable
1[Mail.Model.CostCentre]'.
Joined: 28-Nov-2005
You mapper looks like:
AutoMapper.Mapper.CreateMap<IAEC.SMS.Core.EntityClasses.InstituteFollowUpEntity, InstituteFollowUp>().ForMember(
p => p.FollowUpId, p => p.MapFrom(x => x.Id));
... but then you are trying to map like this:
Select Mapper.Map(Of IQueryable(Of CostCentre), TblCostCentreEntity)(p)
In order to use your map you should materiailze the entities and use your mapping in the last projection (select) as you are doing already. See this snippet:
public class CustomerDto
{
public string Id { get; set;}
public string Name { get; set; }
public string Other { get; set; }
}
...
Mapper.CreateMap<CustomerEntity, CustomerDto>().ForMember(
p => p.Id, p => p.MapFrom(x => x.CustomerId));
...
var dtos = new List<CustomerDto>();
using (var adapter = new DataAccessAdapter())
{
var metaData = new LinqMetaData(adapter);
dtos = (from c in metaData.Customer
select Mapper.Map<CustomerDto>(c)).ToList();
}
That is indeed a custom projection. Now in v3.5 you also can use QuerySpec's projections.
Joined: 06-Sep-2012
Thanks for that. but what if i want to return an Iqueryable object rather an instance of LLBLGenProQuery class? How can i do that or should i do that? I am using Repositorypattern and everywhere they are advising to return an iqueryable object to the View so we can query later if we need. Since i am using LLBLgenPro code (Self-Servicing) and LinqMetaData, it's returning an object of LLBLgenProQuery class and i am sort of confused that should i use LLBLgenproquery or should i use iqueryable?
I am sort of confused and guess in turn confusing my question.
What's the difference between an object returned by LLBLGenProQuery and IQueryable return by System.Linq?
Edit
Sorry guys. My mistake. this code works and returns an iqueryable object.
Public Function GetAllCostCentres() As IQueryable(Of Model.CostCentre) Implements ICostCentreRepository.GetAllCostCentres Mapper.CreateMap(Of TblCostCentreEntity, CostCentre)() Dim metaData As New LinqMetaData Dim q = From p In metaData.TblCostCentre _ Select Mapper.Map(Of CostCentre)(p) Return q End Function