Linq adding items to list in the query - linq

Good day,
I have one problem. I have three Domain objects
public class User
{
public Guid Id { get; set; }
public string Username { get; set; }
public string EmailAddress { get; set; }
public string Password { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
[NotMapped]
public List<string> Roles { get; set; }
//nav prop
public List<User_Role> UserRoles { get; set; }
}
public class User_Role
{
public Guid Id { get; set; }
public Guid UserId { get; set; }
//nav prop
public User User { get; set; }
public Guid RoleId { get; set; }
//nav prop
public Role Role { get; set; }
}
public class Role
{
public Guid Id { get; set; }
public string Name { get; set; }
public List<User_Role> UserRoles { get; set; }
}
I want to create DTO object from them
public class ReturnUserDto
{
public Guid Id { get; set; }
public string Username { get; set; }
public string EmailAddress { get; set; }
public string Password { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public List<string> Roles { get; set; }
}
I have created a controller for it
[Route("api/[controller]")]
[ApiController]
public class UserController : ControllerBase
{
public readonly IUserRepository _userRepository;
public readonly IRoleRepository _roleRepository;
public readonly IUserRoleRepository _userRoleRepository
public UserController(IUserRepository userRepository, IRoleRepository IRoleRepository,
IUserRoleRepository userRoleRepository)
{
_userRepository = userRepository;
_roleRepository = IRoleRepository;
_userRoleRepository = userRoleRepository;
}
[HttpGet]
public async Task<IActionResult> GetAllUsersAsync()
{
var users = _userRepository.GetAllAsync();
var usersDto = users.ConvertToDto(unknow arguments)
}
}
And i am trying achieve it by using static DtoConverstion function
It looks like this
public static IEnumerable<ReturnUserDto> ConvertToDto(this IEnumerable<User> users,
IEnumerable<Role> Role)
{
var returnUserDto = (from user in users
select new ReturnUserDto
{
Id = user.Id,
Username = user.Username,
EmailAddress = user.EmailAddress,
Password = user.Password,
FirstName = user.FirstName,
LastName = user.LastName,
Roles = ?(Something like Role.name)
})
}
How do I achieve it? I understand that I need to use user_roles to get roles from it for a specific user, then add it to DtoConvertion function. I am just not sure how to do it.

Can do it multiple ways.One way is to use the Include() and ThenInclude() option
Instead of _userRepository.GetAllAsync(), add a new method which will get the list of Users along with User Roles and its Roles with it. It will be something like
context.Users
.Include(u => u.UserRoles)
.ThenInclude(u => u.Role).ToList()
Then, in the convert method, something like
public static IEnumerable<ReturnUserDto> ConvertToDto(this IEnumerable<User> users)
{
var returnUserDto = (from user in users
select new ReturnUserDto
{
Id = user.Id,
Username = user.Username,
EmailAddress = user.EmailAddress,
Password = user.Password,
FirstName = user.FirstName,
LastName = user.LastName,
Roles = user.UserRoles.Select(s => s.Role.Name).ToList()
})
}
Refer https://learn.microsoft.com/en-us/ef/ef6/querying/related-data if you are not familiar with the Include() method.
Hope this helps.

Related

automapper issue in nested entity

Entity:
public class AccountEntity: MasterEntity
{
public AccountType AccountType { get; set; }
public DepartmentEntity Department { get; set; }
public string LeadSource { get; set; }
public ResourceEntity AccountManager { get; set; }
public AccountQualificationStatus QualificationStatus { get; set; }
}
public class DepartmentEntity : MasterEntity
{
}
public class ResourceEntity : MasterEntity
{
public string Email { get; set; }
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
}
public abstract class MasterEntity: Entity
{
public string Name { get; set; }
public string Code { get; set; }
}
Model
public class Accounts
{
private string depname;
public int Id { get; set; }
public string Name { get; set; }
public int Code { get; set; }
public string AccountType { get; set; }
public string Department { get; set; }
}
public AccountMappingProfile()
{
CreateMap<Account, AccountTest>().ReverseMap();
CreateMap<Opportunity, OpportunityEntity>().ReverseMap();
CreateMap<Accounts, AccountEntity>().ReverseMap();
CreateMap<Resource, ResourceEntity>().ReverseMap();
CreateMap<Projects, ProjectEntity>().ReverseMap();
}
public static class AccountMapper
{
private static readonly Lazy<IMapper> Lazy = new Lazy<IMapper>(() =>
{
var config = new MapperConfiguration(cfg => {
cfg.ShouldMapProperty = p => p.GetMethod.IsPublic || p.GetMethod.IsAssembly;
cfg.AddProfile<AccountMappingProfile>();
});
var mapper = config.CreateMapper();
return mapper;
});
public static IMapper Mapper => Lazy.Value;
}
I am able to fetch resource details .while I am fetching accounts with department and resources, the value for department is giving me null after automapping.
public async Task<IEnumerable<Accounts>> GetAccounts()
{
try
{
var accounts = await _context.Account.Include(c=>c.Director).ToListAsync();
// accounts = await _context.Account.Include(c => c.Department).ToListAsync();
return AccountMapper.Mapper.Map<List<Accounts>>(accounts);
}
}
controller method:
public async Task<IEnumerable<Accounts>> GetClients()
{
var result = await _repository.GetAccounts();
return result;
}
if I am uncommenting the code to include department, its is giving the object name.
I need to get the department details as well. how can i get that.Department entity is inheriting master entity.

The property is not a navigation property of entity type

I've designed my entities attached in the below diagram.
For this schema I would have written following query in sql to get all the roles, activities, applications for this user in the following way
select * from users u, roles r, userroles ur, roleappactivities raa, applications ap, activities ac
where u.Id = ur.UserId
and ur.RoleId = r.Id
and r.Id = raa.RoleId
and raa.ApplicationId = ap.Id
and raa.ActivityId = ac.Id
and u.id = 1
For the same to be achieved in my core application, I've written following code, which is failing. I ran out of ideas of how to achieve the above query through the following code. Any help much appreciated.
_context.Users
.Include("Roles")
.Include("RoleAppActivities")
.Include("Applications")
.Include("Activities")
.Where(x => x.Id == id)
.Select(x => new User
{
Id = x.Id,
TId = x.TId,
Roles = x.Roles
})
Edit:
Here are my entities
public class User
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public int Id { get; set; }
public string Name { get; set; }
public ICollection<UserRole> Roles { get; set; }
}
public class UserRole
{
public int UserId { get; set; }
public User User{ get; set; }
public int RoleId { get; set; }
public Role Role{get; set;}
}
public class Role
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public ICollection<UserRole> Users { get; set; }
public ICollection<RoleApplicationActivity> RoleApplicationActivity { get; set; }
}
public class RoleApplicationActivity
{
public int Id { get; set; }
public int RoleId { get; set; }
public int ApplicationId { get; set; }
public int ActivityId { get; set; }
public Activity Activity { get; set; }
public Application Application { get; set; }
public Role Role { get; set; }
}
public class Activity
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public int Id { get; set; }
public string Name { get; set; }
public ICollection<RoleApplicationActivity> RoleApplicationActivity { get; set; }
}
public class Application
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public int Id { get; set; }
public string Name { get; set; }
public ICollection<RoleApplicationActivity> RoleApplicationActivity { get; set; }
}
I think that your entity User should have the others collections (Roles ,
RoleAppActivities..). So you can directly load them by using .include(user=> user.Collection) , i think it is more strongly typed than using the .include("string)"..
I've to modify my query to following to fix the issue.
from u in _context.Users
from r in _context.Roles
from app in _context.Applications
from ac in _context.Activities
where u.Id == 1
select u

LINQ query for fetching data using Entity Framework from multiple tables with Lambda expressions and without Join keyword

I want to fetch details of Employee from three tables based on employeeNumber.
Three Tables :
EmployeeDetails (employeeNumber primarykey & userID,designationId Foreignkey)
UserDetails (userId primaryKey)
Designations (designationId primarykey)
UserDetails
public partial class UserDetail
{
public UserDetail()
{
this.EmployeeDetails = new HashSet<EmployeeDetail>();
}
public System.Guid user_id { get; set; }
public string employee_name { get; set; }
public string employee_email { get; set; }
public decimal employee_contactnumber { get; set; }
public virtual ICollection<EmployeeDetail> EmployeeDetails { get; set; }
}
EmployeeDetails
public partial class EmployeeDetail
{
public System.Guid employee_id { get; set; }
public Nullable<System.Guid> user_id { get; set; }
public int employee_number { get; set; }
public Nullable<int> designation_id { get; set; }
public virtual Designation Designation { get; set; }
public virtual UserDetail UserDetail { get; set; }
}
Designations
public partial class Designation
{
public Designation()
{
this.EmployeeDetails = new HashSet<EmployeeDetail>();
}
public int designation_id { get; set; }
public string designation_name { get; set; }
public Nullable<System.DateTime> create_date { get; set; }
public virtual ICollection<EmployeeDetail> EmployeeDetails { get; set; }
}
I'd suggest to add navigation properties to your entity classes if you haven't yet. That would cause EF to inject the join without you having to specify join conditions.
Changed your identifiers to match conventions, otherwise you have to explicitly configure the associations.
public class Employee
{
public int EmployeeId { get; set; }
public int UserDetailId { get; set; }
public UserDetail UserDetail { get; set; }
}
public class UserDetail
{
public int UserDetailId { get; set; }
public string SomeUserDetailProperty{ get; set; }
public ICollection<Employee> Employees { get; set; }
}
This allows for
db.Employees.Select(e => new
{
e.EmployeeId,
e.UserDetail.SomeUserDetailProperty
})
Create a view in your database and fetch data using that view in entityframework
var data = entities.EmployeeDetails.Select(e => new GetUserInfo {designation= e.Designation,userDetail = e.UserDetail, employeeDetail = e }).Where(e => e.employeeDetail.employee_number == number);
This is working fine. Thank you
GetUserInfo class consists of :
public class GetUserInfo{
public UserDetails userDetail {get;set;}
public EmployeeDetails employeeDetail {get;set}
public Designations designation{get;set;}
}

How to use checklistbox to update roles in account in mvc3

I have any Model
public class Account
{
[Key]
public int AccountID { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public string FullName { get; set; }
}
And
public class Role
{
[Key]
public int RoleID { get; set; }
public string RoleKey { get; set; }
public string RoleName { get; set; }
}
And
public class AccountRole
{
[Key]
public int ID { get; set; }
public int AccountID { get; set; }
public string Role { get; set; }
}
I want to use one view update Account and list role to list checkbox. When I checked in checkbox then role to insert in to AccountRole.
Please tell me how to create my View.
Create a holder for a Role + a boolean IsSelected
public class SelectionRoles
{
public bool IsSelected { get; set;}
public Role OneRole { get; set; }
}
use this in your ViewModel as a List, pass it to your View and use it for display, when you submit your form you can check in your controller which roles are checked by looking in your ViewModel at the IsSelected boolean for each record in your SelectionRole List.

asp.net MVC User Friends LazyLoad

If i try to use code first,
The User Class:
public class User
{
[Key]
public Guid ID { get; set; }
[Required(ErrorMessage = "You must pick a user name")]
[DisplayName("User Name")]
public string Username { get; set; }
[Required]
public string FullName { get; set; }
[Required(ErrorMessage = "You give a valid email address")]
[DataType(DataType.EmailAddress)]
public string Email { get; set; }
[Required]
[DataType(DataType.Password)]
public string Password { get; set; }
[Required]
public DateTime CreateAt { get; set; }
public string Image { get; set; }
public bool RemeberMe { get; set; }
public bool Dummy { get; set; }
public virtual ICollection<UserFriend> Friends { get; set; }
}
The UserFriend Class: - hold the relationship between users
public class UserFriend
{
[Key, Column(Order = 0), ForeignKey("User")]
public Guid UserId { get; set; }
public User User { get; set; }
[Key, Column(Order = 1), ForeignKey("Friend")]
public Guid FriendId { get; set; }
public User Friend { get; set; }
public DateTime DateCreated { get; set; }
}
User Repository:
public class UserRepository : IUserRepository
{
public User GetUserByName(string userName)
{
return context.Users.FirstOrDefault(u => u.Username == userName);
}
}
if i try to user this methods:
var userRepo = new UserRepository(new DataContext());
User user = userRepo.GetUserByName(User.Identity.Name);
PROBLEM: user.Friends.first().Friend return null
if i got it right my lazy load not working.
help please...
link to the project - https://github.com/RanDahan/barker
In the contructor of User class you should create new instance of Friends collection
Friends = new HashSet<UserFriend>()
Also, i think navigation properties in UserFirends should also have been declared as virtual.

Resources