How to Map anonymous object in Auto Mapper - c#

Am trying to Map an Anonymous object in auto mapper but am not getting how to do that. Please find my requirement below
Am getting some data from joining 2 tables with only one common column(Id). Am getting Anonymous type data from this query.
var query = (from _vdata in Table1
join entityFind in Table2 on _vdata.id equals entityFind.id
select new { entityFind.FamilyName, entityFind.LastLogin, entityFind.GivenName,
entityFind.Email, entityFind.EmailVerified, entityFind.Uuid, _vdata.Role,
_vdata.Payers, _vdata.Accounts, _vdata.ModifiedOn }).ToList();
Am getting Anonymous data from above query. I have some more list of data in another variable i need to add those data to this list with limited columns having 4-5 columns.
How to do mapping in this situation in AutoMapper or in any other technique
thanks

Since all anonymous types derived from System.Object, I found a solution (workaround) to add mapping from object to your destination type
//Allow to map anonymous types to concrete type
cfg.CreateMap(typeof(object), typeof(ExternalCandle),
MemberList.None);
But please note that for most scenarios this is not the correct solution
For example, if you want to map ORM types - go with this way: Queryable Extensions
I guess that Jimmy bogard won't recommend this solution because of the same reason that CreateMissingTypeMaps was removed from AutoMappers's API -https://github.com/AutoMapper/AutoMapper/issues/3063
So maybe in a future version of AutoMapper this code won't work (I am using AutoMapper 10.1.1 and it worked for me)

You cannot map anonymous type. To achieve the above functionality you can create a Model like below:
public class ResultantData
{
public string FamilyName { get; set; }
public string LastLogin { get; set; }
public string GivenName { get; set; }
public string Email { get; set; }
public string EmailVerified { get; set; }
public string Uuid { get; set; }
public string Role { get; set; }
public string Payers { get; set; }
public string Accounts { get; set; }
public string ModifiedOn { get; set; }
}
Then you can write the above query as below and return the IQueryable of the result:
var query = (from _vdata in Table1
join entityFind in Table2 on _vdata.id equals entityFind.id
select new ResultantData
{
entityFind.FamilyName,
entityFind.LastLogin,
entityFind.GivenName,
entityFind.Email,
entityFind.EmailVerified,
entityFind.Uuid,
_vdata.Role,
_vdata.Payers,
_vdata.Accounts,
_vdata.ModifiedOn
});
When you want to map this result to actual model then you can use ProjectTo method of Automapper as below:
var result = query.ProjectTo<ResultantDataModel>().ToList();
I have used below class as result model:
public class ResultantDataModel
{
public string FamilyName { get; set; }
public string LastLogin { get; set; }
public string GivenName { get; set; }
public string Email { get; set; }
public string EmailVerified { get; set; }
public string Uuid { get; set; }
public string Role { get; set; }
public string Payers { get; set; }
public string Accounts { get; set; }
public string ModifiedOn { get; set; }
}

Related

LINQ Projection and loading child objects

Having an issue with projection and getting child objects to load. The following is simplified code to represent the logic I'm trying to implement, not the actual code.
public class TicketItem
{
public int TicketItemId { get; set; }
public string TicketReason { get; set; }
public Station Station { get; set; }
public TicketOwner TicketOwner { get; set; }
}
public class Station
{
public int StationId { get; set; }
public string Name { get; set; }
}
public class TicketOwner
{
public int TicketOwnerId { get; set; }
public Employee Employee { get; set; }
public Organization Organization { get; set; }
}
public class Employee
{
public int EmployeeId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class Organization
{
public int OrganizationId { get; set; }
public string Code { get; set; }
public string Name { get; set; }
}
public class CommonReasons
{
public int CommonReasonId { get; set; }
public string Reason { get; set; }
}
public TicketItem GetById(int id)
{
var query = from i in _dataContext.TicketItems
.Include("Station")
.Include("TicketOwner.Employee")
.Include("TicketOwner.Organization")
join r in _dataContext.CommonReasons on i.TicketReason equals r.CommonReasonId.ToString() into r1
from r2 in r1.DefaultIfEmpty()
where i.TicketItemId == id
select new TicketItem {
TicketItemId = i.TicketItemId,
TicketReason = r2.Reason == null ? i.Reason : r2.Reason,
Station = i.Station,
TicketOwner = i.TicketOwner
};
return query
.AsNoTracking()
.FirstOrDefault();
}
Most the code is self-explanatory. The part that is indirectly causing the trouble would be the relationship between TicketItem.TicketReason property (a string) and the CommonReasons entity. From the user interface side, the end-user has an input field of "Reason", and they can select from "common" reasons or input an adhoc reason. They original developer chose to have the TicketReason property contain either the key ID from the CommonReasons table (if the user selected from drop-down) or the adhoc reason typed in.
So, to handle this logic in the linq query, the only way I have found is to do a left join between TicketItem.TicketReason and CommonReasons.CommonReasonId, then use projection to modify the TicketReason column returning either the common reason text or adhoc text. If there is a different way to do this that would get me around the trouble I'm having with projection/include, I'm all ears.
For the "reason" logic, this query works, returning the proper text. The trouble is that none of the "grand-child" objects are returning, i.e. TicketItem.TicketOwner.Employee, TicketItem.TicketOwner.Organization. How do I get those objects to return also?
Changing the structure of the tables would be an absolute last resort, just based on the amount of code that would have to change. There are other spots in the code that are using the above logic but don't need the child objects.
Any help would be appreciated. Hope I've explained enough.

Complex mapping in dapper without subqueries

If I have an object like
class Thing
{
public string A { get; set; }
public string B { get; set; }
public string C { get; set; }
public string D { get; set; }
}
Dapper works really well with:
return conn.QuerySingle<Thing>(
#"SELECT A, B, C, D
FROM [Thing] WHERE Id = #id", new { id });
But what if my class structure is
class Thing
{
public string A { get; set; }
public string B { get; set; }
public IEnumerable<Stuff> { get; set; }
}
class Stuff
{
public string C { get; set; }
public string D { get; set; }
}
How can I get Dapper to map to that structure, assuming the Enumerable will always contain 1 item in the Enumerable so in reality I am just representing the same data in a different way.
The Dapper tutorials I've seen are quite complex and contain subqueries, but ideally my query shouldn't change because it already returns all the data that should map to the new structure.
Any ideas?
You have to create your own Custom Type Mapper. I've written an article and some samples here:
https://medium.com/dapper-net/custom-type-handling-4b447b97c620

Linq query to include items with on a join object

I'm trying to get a collection of objects using a Linq query that would include child objects. I can do an include on the main table and get results. But if I do an include on one of the tables I join to, I do not get the object that should be returned by the include.
Here are my models:
public class RequestReviewViewModel
{
public Guid RequestId { get; set; }
public Guid ResourceToReviewId { get; set; }
public Guid ReviewRequiredId { get; set; }
public ReviewRequired ReviewRequired { get; set; }
}
public class Required : BaseEntity
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
public Guid RequiredId { get; set; }
[Display(Name = "Review Name")]
public int ReviewNameId { get; set; }
[ForeignKey("ReviewNameId")]
public ReviewName ReviewName { get; set; }
}
Here's the linq query I'm trying. The line Required.Include(revr => revr.ReviewName) doesn't seem to do anything:
var requests = (from req in Request.Include(rr => rr.Resource)
join revreq in Required.Include(revr => revr.ReviewName)
on req.ReviewRequiredId equals revreq.RequiredId
where req.IsActive
select new RequestReviewViewModel
{
RequestId = req.RequestId,
ResourceToReviewId = req.ResourceToReviewId,
ReviewRequiredId = req.ReviewRequiredId,
Required = revreq
};
requests.FirstOrDefault().Required.ReviewName.Dump();
While requests.FirstOrDefault().Required.ReviewNameId has a value, the ReviewName object is null. The relationship is in the database, and was created by Code First.
Your ReviewName is not declared virtual which enables eager/lazy loading (and automatic change-tracking to be complete). Add virtual and it should work:
public virtual ReviewName ReviewName { get; set; }

Combine an IQueryable and a List to a new class (type)

I have a LINQ query written which returns a list of services, including an ID (resourceID) for who performed this service. I need to take this resourceID and use it as an input parameter for an existing method which will return an IQueryable result set of the resource details.
What I need to do from here is take some of the resource details returned from the GetResource method (iQueryable type) and add it to a list of a new class "People" along with a list of the services. i.e. a person will likely have more than one service. The end result is a List of people with properties from the resource result and a sublist of services performed by each person.
Essentially there are two methods that run linq queries that return a result sets of different types, I need to combine those results into a new type but I only need some of the fields returned by both.
I already have a linq query that returns a list of services:
public class Services
{
public string Activity { get; set; }
public DateTime DateProvided { get; set; }
public Int32? ResourceId { get; set; }
public string ResourceName { get; set; }
public string ServiceCode { get; set; }
public string ServiceStatus { get; set; }
There is another method that will return an IQueryable of Providers:
public long EId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int? ResourceId { get; set; }
public string EmailAddress { get; set; }
~ 50 other fields...
What I need to do is take the List of Services, lookup the Provider and combine those results into this new class (type):
public string EmailAddress { get; set; }
public long EId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public List<Services> Services { get; set; }
My first time asking here, so please let me know if I am unclear or if you need additional details.
Thanks in advance
Maybe something like
var services = GetServices();
var providers = GetProviders();
var combined = providers.Select(x =>
new{
EId,
Firstname,
Lastname,
EmailAddress,
Services = services.Where(
y=> y.ResourceId == x.ResourceId
).ToList()
});

Solr returning 400

here is the object model.When i try to commit Product to Solr, returning unknown field loca
public class Product
{
[SolrUniqueKey("id")]
public string Id { get; set; }
[SolrField("manu")]
public string Manufacturer { get; set; }
[SolrField("cat")] // cat is a multiValued field
public ICollection<string> Categories { get; set; }
[SolrField("price")]
public decimal Price { get; set; }
[SolrField("inStock")]
public bool InStock { get; set; }
[SolrField("loca")]
public Location Location { set; get; }
}
public class Location
{
[SolrField("zipcode")]
public int Zip { set; get; }
[SolrField("country")]
public string Country { set; get; }
}
Is nested classes legal with solr?
why is it failing to store? when i remove [SolrField("loca")] it works fine.
how do you store such classes?
You cannot do nested classes in Solr. So you will need to flatten the location information into the Product class. However, you can then represent it a nested class within your application, by mapping the data into/out of Solr as needed.
As an example, update your Solr schema to store a loca_zipcode and loca_country field and then map those perhaps in a new SolrProduct class defined like the following:
public class SolrProduct
{
[SolrUniqueKey("id")]
public string Id { get; set; }
[SolrField("manu")]
public string Manufacturer { get; set; }
[SolrField("cat")] // cat is a multiValued field
public ICollection<string> Categories { get; set; }
[SolrField("price")]
public decimal Price { get; set; }
[SolrField("inStock")]
public bool InStock { get; set; }
[SolrField("loca_zip")]
public int Zip { set; get; }
[SolrField("loca_country")]
public string Country { get; set; }
}
Then you can use something like AutoMapper to map the SolrProduct flattened class to your Product class with the nested Location class.
Another alternative would be to use dynamic fields in Solr and the dynamic mapping support in SolrNet using a Dictionary. Please see the SolrNet - Mapping section of the SolrNet wiki for more details and examples.

Categories