I am having employee table:
public class Employee
{
public int Id {get;set;}
public string FirstName {get;set;}
public string LastName {get;set;}
public int SupervisorId {get;set;}
}
SupervisorId is a foreign key from the same table (Employee) that points to other employee.
Then I have something like "EmployeeSupervisorDto"
public class EmployeeSupervisorDto
{
public int Id {get;set;}
public string FirstName {get;set;}
public string LastName {get;set;}
public string FullNameSupervisor {get;set;}
}
What I want to achievie is to use automapper to set FullNameSupervisor automaticly to combination of FirstName and LastName of supervisor.
Tried so far to do something like this:
cfg.CreateMap<Employee, EmployeeSupervisorDto>()
.ForMember(e => e.FullNameSupervisor, m => m.MapFrom(p => $"{p.LastName} {p.FirstName}"));
But I have no idea how to do reference to Id that points out to employee id that is supervisor of given employee.
To use the below solution, you will need to inject your data context to the auto mapper profile class (via constructor parameter), and also, in the ConfigureServices, add the DI of the automapper profile as shown in https://stackoverflow.com/a/49198279/9907597.
Create a method in the AutoMapper profile class:
public string GetEmployerFullName(int supervisorEmpId)
{
var supervisor = db.Employees.Find(supervisorEmpId);
return supervisor.FirstName + " " + supervisor.LastName;
}
Then create the mapping in the automapper profile class constructor as:
CreateMap<Employee, EmployeeSupervisorDto>()
.ForMember(e => e.FullNameSupervisor, m => m.MapFrom(p => GetEmployerFullName(p.SupervisorId)));
You can use either ValueResolver or something like this code if you want to use it once and not generally:
Mapper.CreateMap<Employee, EmployeeSupervisorDto>()
.ForMember(e => e.FullNameSupervisor, o => o.ResolveUsing(m => { return m.LastName + m.FirstName}));
May help you,
i try with linq approach :
public class Employee
{
public int Id {get;set;}
public string FirstName {get;set;}
public string LastName {get;set;}
public int SupervisorId {get;set;}
}
it give you the list of employe with sup FullNameSupervisor
var Employeelist = new List<Employee>() {...};
var EmployeeWithSup = from ep in Employeelist
join epsup in Employeelist on ep.SupervisorId equals epsup.Id
select new { Id = ep.Id,FirstName = ep.FirstName,LastName = ep.LastName,
SupervisorId = ep.SupervisorId,FullNameSupervisor = epsup.FirstName + " " + epsup.LastName };
If you want to do joins use automapper ,try the follow link :
AutoMapper to join records from 2 tables into single IEnumerable viewmodel
Related
There are 3 entities, let's say they are presented in this way:
**1 - entity**
class A
int id ;
int Name;
[Foreign key]
int id_B;
List C;
**2 - entity**
class B
int id ;
int Name;
List A;
**3 - entity**
class C
int id;
int Name;
[Foreign Key]
int id_A;
created an entity DTO (Everything is the same only without foreign keys)
1
class ADTO
int id ;
int Name;
List C;
2
class BDTO
int id ;
int Name;
List A;
3
class CDTO
int id;
int Name;
Now the request looks like this:
var quer = (await _context.A
.Include(b => b.B)
.Include(c => c.C)
.Where(u => u.Id == 1).ToListAsync())
.Select(a => new ADto
{
Id = a.Id,
//How to get information about entity B here by converting to DTO
C = a.C.Select(cdto => new CDTO{ Id = cdto.Id, Name = cdto.Name}).ToList(),
});
How to get information about entity B here by converting to DTO?
If you are querying "A" as your top-level entity then I believe you're just missing a navigation property to it's associated "B". (As it contains the B_Id FK)
1 - entity
public class A
{
public int id { get; set; }
public string Name { get; set; }
[ForeignKey("B")]
public int id_B { get; set; }
public virtual B B { get; set; }
public virtual ICollection<C> Cs { get; set;} = new List<C>();
}
Then when you project your Entities to DTOs using Select:
var query = (await _context.A
.Where(a => a.Id == 1)
.Select(a => new ADto
{
Id = a.Id,
B = new BDTO { Id = a.B.Id /* ... */ },
Cs = a.Cs.Select(c => new CDTO{ Id = c.Id, Name = c.Name}).ToList(),
}).Single();
Note that when using .Select you do not need to use .Include to reference related entities, that is only used to eager load related entities where you want to return an entity graph. (Such as when reading the entities to update values from DTOs) Also, be wary of using any ToList operations prior to using a Select as this will load entities into memory before applying things like filters, and negates the optimization of queries to fill just what Select needs.
});
Normally, I would suggest you implement an interface, that is provided on the constructor of the resulting object
so:
public interface IDbOjbect{
int Id {get;set;}
string Name{get;set;}
}
and then on your DTO object
public Class DtoObject {
public DtoOjbect(IDbOjbect source)
{
//Mapping done here.
}
}
Because then you can implement the interface on any persistence layer object, and the mapping will still work.
Because then the linq query is simply:
DbOjbectList.Select(x => new DtoObject(x));
provided DtoOjbect implements the interface.
your C would look like this:
public partial class C {
public int id {get;set;}
public string Name {get;set;}
}
public partial class C : IDbOjbect {
}
and your CDTO would look like:
public Class CDTO{
public int Id {get;set;}
public string Name {get;set;}
public CDTO(IDbOjbect source)
{
Id = source.Id;
Name = source.name;
}
}
Want to be able to make a DTO from B?
Implement IDbOjbect on your B
by using
public partial class B {
public int id {get;set;}
public string Name {get;set;}
}
public partial class B : IDbOjbect {
}
and now any C or B can be made into a CDTO.
Best part is, you can make a generic method for your B and C, use the "Where" keyword after you generic definition, and then use the Interface as the type, now you can make a single method that does the same thing based on what has the interface implementation, and this will also work for A, if you implement the interface on A.
Without further modification.
So now that you are asking questions, you original question doesn't, lets expand.
Lets say you have a ResumeInfo Object that only B has available.
You then use the NullPointer pattern together with interface segregation principle.
So you create an interface on your resumeInfo class
Example:
public interface IResumeInfo
{
string PlaceOfEmployment {get;set;}
DateTime StartOfEmployment {get;set;}
DateTime? EndOfEmployment {get;set;}
}
Then on your ResumeInfo Object:
public partial class ResumeInfo
{
string PlaceOfEmployment {get;set;}
DateTime StartOfEmployment {get;set;}
DateTime? EndOfEmployment {get;set;}
}
public partial class ResumeInfo : IResumeInfo
{
}
Then lets say you want a single DTO object:
public class DTOUserAndResume
{
public int id {get;set;}
public string Name {get;set;}
string PlaceOfEmployment {get;set;}
DateTime StartOfEmployment {get;set;}
DateTime? EndOfEmployment {get;set;}
public DTOUserAndResume(IDbOjbect source, IResumeInfo resumeInfo)
{
Id = source.Id;
Name = source.name;
PlaceOfEmployment = resumeInfo.PlaceOfEmployment;
StartOfEmployment = resumeInfo.StartOfEmployment ;
EndOfEmployment = resumeInfo.EndOfEmployment ;
}
}
Now on B? I think you said you have resume data, but not on C?
you implement the IResumeInfo on both, but on B, you just get whatever data is there, but on C that has no data? NullOjbect Pattern.
Implement the interfacce, but make it return nothing.
So PlaceOfEmployment is always "" or Null.
Start data is always 1900-01-01 00:00:00 or whatever you want "nothing" to be on a not nullable object, and null on the end of employment.
So you simply claim that the data is the equavilant of a none-existing data set, because, it doesn't have a dataset to provide.
But you dont need to make a new DTO, you can just update the constructor on CDTO, it will also work fine. It might just get a bit confusing in regards to naming and stuff.
This should result in a call that looks like:
C = a.C.Select(cdto => new CDTO{cdto, cdto.ResumeInfo}).ToList();
For update using entity frame work , I have a DTO exposed to user with all properties but few properties are assigned with values.
Example
public class Employee
{
public int Id {get;set;}
public string Name {get;set;}
public Datetime CreatedDateTime {get;set;}
public Datetime UpdatedDateTime {get;set;}
}
public class EmployeeDTO
{
public int Id {get;set;}
public string Name {get;set;}
[JsonIgnore]
public Datetime CreatedDateTime {get;set;}
[JsonIgnore]
public Datetime UpdatedDateTime {get;set;}
}
Now The Dto is been populated
EmployeeDto e = new EmployeeDto ()
{
Id =1,
Name = "xxxxxxxxx"
}
Now we have called the method to update
public bool Update(EmployeeDto e )
{
var repo = _dbset.Employee.Get(x => x.id == e.Id)
var d = _mapper.Map<Employee,EmployeeDto>(repo,e);
_dbset.Employee.UpdateAsync(d);
}
** but here on mapping the Created Date and Update Date are set to default values which is giving me an SQL exception**
Please do help me in this case . Sorry If I am not clear
Add this line in your ModelMappingProfile class, it will ignore the properties you'll specify. You also check this link for understanding.
https://dotnettutorials.net/lesson/ignore-using-automapper-in-csharp/
CreateMap<EmployeeDTO, Employee>().ForMember(dest => dest.CreatedDateTime, opts => opts.Ignore()).ForMember(dest => dest.UpdatedDateTime, opts => opts.Ignore());
I have a class that owns a list of entities:
public class Dad
{
public long Id{get;set;}
public string Name{get;set;}
public string SecretName{get;set;}
public List<Kid> Kids{get;set;}
}
public class Kid
{
public long Id{get;set;}
public string Name{get;set;}
public string SecretName{get;set;}
public Dad Dad {get;set;
}
I am trying to specify what columns to select in the Kids that are owned by Dad:
var DadAPIResponse = _context.Dads
.Where(o.Id == Id)
.Select(x => new {
Id = x.Id,
Name = x.Name
// Here, I need something like
// Kids = {Id, Name}
}).AsNoTracking()
.FirstOrDefault();
My intention is to return a list of Dads but only show their Id, Name and only show the Id and Name of each of the Kids owned by that Dad.
I am using EF Core 2.1
You should separate your entity model from the model you are returning and only include the needed properties of each type as:
public class DadModel
{
public long Id{get;set;}
public string Name{get;set;}
public List<Kid> Kids{get;set;}
}
...and:
public class KidModel
{
public long Id{get;set;}
public string Name{get;set;}
}
Since this new Kid-model does not have a reference to its Dad, you also avoid any kind of circular reference issue.
You may then select the kids of each dad by:
var response = _context.Dads
.Where(d.Id == Id)
.Select(d => new DadModel{
Id = d.Id,
Name = d.Name
Kids = d.Kids.Select(k => new KidsModel
{
Id = k.Id,
Name = k.Name
}).ToList()
}).AsNoTracking()
.FirstOrDefault();
This is structure of data, I get back from NHibernate Query
public Class PaperResult
{
public Guid SubjectId {get;set}
public Guid StudentId {get;set}
public string Name {get;set}
public string Email {get;set}
public int Marks {get;set}
}
and my queries is
var resultEntities = _repository.Query<PaperResult>().where(t => t.Id == testId)
studentResults = resultEntities.GroupBy(x => x.StudentId)
which returns, IQueryable, Now I'm projecting it into the class
public Class StudentResult
{
public Guid StudentId {get;set}
public string Name {get;set}
public string Email {get;set}
public int Marks {get;set}
public IEnumerable<PaperResult> PaperResults {get;set;}
}
I have tried to flatten the result using linq below but Nhibernate is throwning "The method or operation is not implemented.".
from paperResult in studentResults
let studentResult = paperResult.First()
select new StudentResult()
{
StudentId =studentResult.StudentId,
Name =studentResult.Name,
Email =studentResult.Email,
Marks =studentResult.Marks,
PaperResults =resultEntities.Where(x => x.StudentId ==studentResult.StudentId
select new PaperResult(){...}.ToList()
}
Note: the code is a skeletal code.
Regards,
You should be able to do a projection to an anonimous type.
Then project to your desired type:
q.AsEnumerable().Select(...)
I have a source and destination object like so:
Source:
public class Team{
public string TeamName{get; set;}
public string List<Person> {get; set;}
}
public class Person{
public string FullName {get; set;}
}
Destination:
public class MyDTOClass{
public string TeamName;
public string PersonName;
}
I basically want to flatten a one-to-many relationship, duplicating the Name property, so the result would be:
MyDtoClass.TeamName= "X";
MyDtoClass.PersonName= "Y";
MyDtoClass.TeamName= "X";
MyDtoClass.PersonName= "Z";
Is there a way to do this with automapper?
I don't think AutoMapper can automatically go from a single Team to an array/collection of MyDTOObjects. However, it should be pretty easy to do what you want with LINQ:
var flattened = from p in team.Persons
select new MyDTOClass { TeamName = team.Name, PersonName = p.FullName}
I just started using Automapper, but here is solution I was able to come with:
Func<Team[], IEnumerable<MyDTOClass>> getPersonsFromTeams = (teams) => new IEnumerable<MyDTOClass>
{
teams.SelectMany(s => s.Persons, (t, person) => new MyDTOClass(team.TeamName, person))
};
mapper.CreateMap<Company, CompanyDTOs>()
.ForMember(d => d.Persons, o => o.ResolveUsing(s => s.getPersonsFromTeams(s.Teams)));