How to shape return data? - c#

While returning data in Postman, I receive full user information such as password hash and password salt. My idea is to return only his username, so that it looks like "user" : "tom" without his data. I should use automapper ? Or how to set the Dto's to return correct data. Any tips ?
public async Task < ActionResult < ProductDto[] >> AddProduct(string username,
ProductDto productDto)
{
User u = await _context.Users
.Where(x => x.UserName == username)
.Include(x => x.Products)
.SingleOrDefaultAsync();
if (u != null)
{
var product = new Product
{
Name = productDto.Name,
Price = productDto.Price,
UserId = u.Id
};
u.Products.Add(product);
await _context.SaveChangesAsync();
}
return u.Products.ToArray();
}
public class Product : BaseEntity
{
public string Name { get; set; }
public decimal Price { get; set ;}
public User User { get; set; }
public int UserId { get; set; }
}
public class ProductDto
{
public string Name { get; set; }
public string Username { get; set; }
public decimal Price { get; set; }
}
Output in postman: https://i.stack.imgur.com/vNi7J.png

You are returning an array of Product objects, but it seems that what you really want is to return an array of ProductDto objects.
You can use the following code to construct the array of ProductDto objects. Insert it after the if (u != null) check:
if (u != null)
{
var product = new Product
{
Name = productDto.Name,
Price = productDto.Price,
UserId = u.Id
};
u.Products.Add(product);
await _context.SaveChangesAsync();
}
else
{
return new ProductDto[] {};
}
var productDtos = new ProductDto[u.Products.Count];
for (var i = 0; i < u.Products.Count; i++)
{
productDtos[i] = new ProductDto
{
Name = product.Name,
Username = product.User.UserName,
Price = product.Price
};
}
return productDtos;
Alternatively, you can use LINQ:
if (u != null)
{
var product = new Product
{
Name = productDto.Name,
Price = productDto.Price,
UserId = u.Id
};
u.Products.Add(product);
await _context.SaveChangesAsync();
}
else
{
return new ProductDto[] {};
}
var productDtos = u.Products
.Select(p => new ProductDto
{
Name = p.Name,
Username = p.User.UserName,
Price = p.Price
})
.ToArray();
return productDtos;

Related

Iterate through nested collection and form org structure with Parent

I have a batch of users defined with that model.
I need to iterate inside Manager nesting while manager is not null and create Departments entities with parents relation. I have an example of code what I already have, so I post it here.
What I already have:
public class AdUserModel
{
public string UserName { get; set; }
public AdUserModel Manager { get; set; }
}
...
List<UserDepartment> userDepartmentsToAdd = new List<UserDepartment>();
List<Department> newDeps = new List<Department>();
RecurseDepartments(adUser);
var userDepartment = new UserDepartment
{
User = user,
PositionName = adUser.PositionName,
Department = newDeps.FirstOrDefault(x => x.Name == adUser.DepartmentName),
IsHeadUser = user.SubordinateUsers?.Any() ?? false
};
userDepartmentsToAdd.Add(userDepartment);
void RecurseDepartments(AdUserModel model)
{
var department = new Department();
var existDep = newDeps.FirstOrDefault(x => x.Name ==
model.DepartmentName);
if (existDep == null)
{
department.Name = model.DepartmentName;
}
if (model.Manager is not null)
{
if (newDeps.FirstOrDefault(x => x.Name == model.Manager.DepartmentName) == null)
{
var parentDepartment = new Department
{
Name = model.Manager.DepartmentName
};
department.ParentDepartment = existDep ?? department;
if (existDep == null)
{
newDeps.Add(department);
}
newDeps.Add(parentDepartment);
}
if (model.Manager.DepartmentName != model.DepartmentName)
{
RecurseDepartments(model.Manager);
}
}
}
Thanks for any help in advance, being stuck here for some reason.

Bind Dto with model and just return one Dto

First of all look at my code: this is ConceptDto:
public Guid ConceptId { get; set; }
public string ConceptName { get; set; }
public string ConceptLatinName { get; set; }
public List<ConceptSubDto> ConceptSubSidiary { get; set;}
This is the ConceptSubDto:
public Guid ConceptSubId { get; set; }
public string ConceptSubName { get; set; }
and I have domains like that.
Now this is my application layer that have logic I want to get these by id and return just one ConceptDto but I don't have any idea have to map these dtos with domain models:
public async Task<ConceptManagementDto> GetConceptById(Guid id)
{
var concept = await _conceptManagementRepository.Query()
.Include(x => x.conceptSubSidiaries)
.GetOneAsync(x => x.Id == id);
return new ConceptManagementDto
{
ConceptManagementId = concept.Id,
ConceptName = concept.ConceptName,
ConceptLatinName = concept.ConceptLatinName,
ConceptSubSidiary = ??
};
}
This query should effective if your DTO has less fields:
public async Task<ConceptManagementDto> GetConceptById(Guid id)
{
return await _conceptManagementRepository.Query()
.Where(x => x.Id == id)
.Select(x = new ConceptManagementDto
{
ConceptManagementId = x.Id,
ConceptName = x.ConceptName,
ConceptLatinName = x.ConceptLatinName,
ConceptSubSidiary = x.ConceptSubSidiaries
.Select(sub => new ConceptSubDto
{
ConceptSubId = sub.ConceptSubId,
ConceptSubName = sub.ConceptSubName
})
.ToList()
}).First();
}

Map list manually from context

Initially I was using automapper for this but its seems way harder for me to implement it.
Basically, I just want to return an empty list instead of null values. I can do this on projects level but not on teammates level. The API must not return a null because the UI that consumes it will have an error.
Sample of my implementation below:
Projects = !Util.IsNullOrEmpty(x.Projects) ? x.Projects : new List<ProjectsDto>(),
Ill highly appreciate if someone can guide me on how to manually map this with null/empty checking.
If you can also provide and example using automapper that too will be very helpful.
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public List<ProjectsDto> Projects { get; set; }
}
public class ProjectsDto
{
public string Status { get; set; }
public List<TeammatesDto> Teammates { get; set; }
}
public class TeammatesDto
{
public string TeammateName { get; set; }
public string PreviousProject { get; set; }
}
//Get by Id
var employee = await _context.Employees
.Where(x => x.id.Equals(request.Id)
.FirstOrDefaultAsync(cancellationToken);
//Map employee
EmployeeDto ret = new EmployeeDto()
{
Id = employee.id,
Name = employee.Name,
Projects = null //TODO: map manually
}
//Get all employees
var employees = await _context.Employees.AsNoTracking()
.ToListAsync(cancellationToken);
//Map here
IList<EmployeeDto> list = new List<EmployeeDto>();
foreach (var x in employees)
{
EmployeeDto dto = new EmployeeDto()
{
Id = x.id,
Name = x.Name,
Projects = null //TODO: map manually
};
list.Add(dto);
}
return list;
Instead of materializing full entities, do the following:
var query = _context.Employees
.Select(e = new EmployeeDto
{
Id = e.id,
Name = e.Name,
Projects = e.Projects.Select(p => new ProjectDto
{
Status = p.Status,
Templates = p.Templates.Select(t => new TemplateDto
{
TeammateName = t.TeammateName,
PreviousProject = t.PreviousProject
}).ToList()
}).ToList()
}
);
var result = await query.ToListAsync();

Why can't I select specific columns from collection using lambda expression?

using the lambda expression I just want to select 2 columns but it throws error.
Code:
public List<Certificates> GetClientsList(string certificationNo = "")
{
List<Certificates> certificatesList = new List<Certificates>();
var query = uow.CertificatesRepository.GetQueryable().AsQueryable();
if (!string.IsNullOrEmpty(certificationNo))
{
query = query.Where(x => x.CertificationNo.Contains(certificationNo)).Select(n => new { ClientName= n.Client, ID= n.CertificatesID});
}
certificatesList = query.ToList();
return certificatesList;
}
Certificates class:
public class Certificates
{
public int CertificatesID { get; set; }
public string FileName { get; set; }
[Required]
[Display(Name = "Certification No")]
public string CertificationNo { get; set; }
[Required]
[Display(Name = "Issue Date")]
public string IssueDate { get; set; }
[Required]
public string Details { get; set; }
[Required]
public string Client { get; set; }
}
Error:
Cannot convert Anonymous querable type to List
Why do you need it converted to Queryable first? what type does uow.CertificatesRepository.GetQueryable() return?
public List<Certificates> GetClientsList(string certificationNo = "")
{
var query = uow.CertificatesRepository.GetQueryable(); // do ToList here if it is IQuerable, but as it seems it was not.
return query.Where(x=>x.CertificationNo.Contains(certificationNo)).Select(x=> new Certificates(){ClientName= n.Client, ID= n.CertificatesID}).ToList();
}
You are probably looking for something like this (depending on the return type of CertificatesRepository)
public List<Certificates> GetClientsList(string certificationNo = "")
{
var query = uow.CertificatesRepository;
if (string.IsNullOrEmpty(certificationNo))
return query.ToList();
return query.Where(x => x.CertificationNo.Contains(certificationNo))
.ToList();
}
Update
The thing is want is to select 2 columns only
public List<Certificates> GetClientsList(string certificationNo = "")
{
var query = uow.CertificatesRepository;
if (string.IsNullOrEmpty(certificationNo))
return query.Select(n => new Certificates { ClientName = n.Client, ID = n.CertificatesID})
.ToList();
return query.Where(x => x.CertificationNo.Contains(certificationNo))
.Select(n => new Certificates { ClientName = n.Client, ID = n.CertificatesID})
.ToList();
}
or
public List<(int ID , string ClientName)> GetClientsList(string certificationNo = "")
{
var query = uow.CertificatesRepository;
if (string.IsNullOrEmpty(certificationNo))
return query.Select(n => (ID = n.CertificatesID, ClientName = n.Client))
.ToList();
return query.Where(x => x.CertificationNo.Contains(certificationNo))
.Select(n => (ID = n.CertificatesID, ClientName = n.Client))
.ToList();
}
Your Select returns anonymous objects. These anonymous objects of course can't be converted to Certificates.
If you really want to use your Certificates class, then you could just create new objects in your select:
public List<Certificates> GetClientsList(string certificationNo = "")
{
List<Certificates> certificatesList = new List<Certificates>();
var query = uow.CertificatesRepository.GetQueryable().AsQueryable();
if (!string.IsNullOrEmpty(certificationNo))
{
query = query.Where(x => x.CertificationNo.Contains(certificationNo)).Select(n => new Certificates{ Client = n.Client, CertificatesID = n.CertificatesID});
}
certificatesList = query.ToList();
return certificatesList;
}
A better solution would probably be to create a new class which only contains the two required properties.
A third possibility is to return a List<dynamic> instead. But then you are not strongly typed anymore.

asp.net mvc c# listing categories recursively

I am trying to fill a list with my categories data.
My categories have cascade format. They are formatted recursively in my database.
Here is my model object.
public class CategoriesDTO
{
public int Id { get; set; }
public int Level { get; set; }
public string Name { get; set; }
public List<CategoriesDTO> Subs { get; set; }
}
So, in my business layer, i am trying to call this method like this:
DAO.Categories(0);
it will start with "Level==0" condition and then it will go on..
but i couldn't manage the Data Access Layer. I tried this:
public List<CategoriesDTO> Categories(int PrmLevel)
{
List<CategoriesDTO> DTO = new List<CategoriesDTO>();
//DB is my dbcontext.
DTO = DB.Categories.Select(x => new CategoriesDTO()
{
Id = x.Id,
Level = x.Level,
Name = x.Name
}).Where(y => y.Level == PrmLevel).ToList();
foreach (var item in DTO)
{
//im stucked
}
return DTO;
}
}
public List<CategoriesDTO> Categories(int PrmLevel)
{
List<CategoriesDTO> DTO = new List<CategoriesDTO>();
//DB is my dbcontext.
DTO = DB.Categories.Select(x => new CategoriesDTO()
{
Id = x.Id,
Level = x.Level,
Name = x.Name
}).Where(y => y.Level == PrmLevel).ToList();
foreach (var item in DTO)
{
item.Subs = ((PrmLevel + 1) <= MaxLevel) ? Categories(PrmLevel + 1) : null;
}
return DTO;
}
}
public List<CategoriesDTO> Categories(int PrmLevel)
{
List<CategoriesDTO> DTO = new List<CategoriesDTO>();
//DB is my dbcontext.
DTO = DB.Categories.Select(x => new CategoriesDTO()
{
Id = x.Id,
Level = x.Level,
Name = x.Name
}).Where(y => y.Level == PrmLevel).ToList();
foreach (var item in DTO)
{
int CountSub = 0;
CountSub = DB.Categories.Where(x => x.Level == item.Id).ToList().Count();
if (CountSub!=0)
{
item.Subs = Categories(item.Id).ToList();
}
}
return DTO;
}
}

Categories

Resources