Expression of type 'System.Collections.Generic.List`1[API.Entities.CompanySetting]' cannot be used for parameter of type 'System.Linq.IQueryable - asp.net

I am trying to find a simple way using AutoMapper to return all companies that are linked to a specific User Id in a many-to-many relationship scenario. I followed the SO Automapper many to many mapping but I get the error message "Expression of type 'System.Collections.Generic.List`1[API.Entities.CompanySetting]' cannot be used for parameter of type 'System.Linq.IQueryable" when trying to follow the logic.
My AppUser entity:
public class AppUser
{
public int Id { get; set; }
public string UserName { get; set; }
public virtual ICollection<AppUserCompanySetting> AppUserCompanySettings { get; set; } = new List<AppUserCompanySetting>();
}
My CompanySetting entity:
public class CompanySetting
{
public int Id { get; set; }
public string CompanyName { get; set; }
public string CompanyRegistrationNumber { get; set; }
public bool isActive { get; set; }
public bool isArchived { get; set; }
public virtual ICollection<AppUserCompanySetting> AppUserCompanySettings { get; set; } = new List<AppUserCompanySetting>();
}
And I have the Join table
public class AppUserCompanySetting
{
public int AppUserId { get; set; }
public virtual AppUser AppUser { get; set; }
public int CompanySettingsId { get; set; }
public virtual CompanySetting CompanySettings { get; set; }
}
I then created a CompanySettingDto
public class CompanySettingDto
{
public int Id { get; set; }
public string CompanyName { get; set; }
public string CompanyRegistrationNumber { get; set; }
public bool isActive { get; set; }
public bool isArchived { get; set; }
}
And a MemberDto:
public class MemberDto
{
public int Id { get; set; }
public string Username { get; set; }
public string PhotoUrl { get; set; }
public string KnownAs { get; set; }
public int TimeActive { get; set; }
public DateTime LastActive {get; set;}
public ICollection<PhotoDto> Photos { get; set; }
public ICollection<CompanySettingDto> CompanyInformation { get; set; }
}
I then tried Automapper to bring the relationships between the User and the Company Information I require:
public class AutoMapperProfiles : Profile
{
public AutoMapperProfiles()
{
CreateMap<AppUser, MemberDto>()
.ForMember(dest => dest.CompanyInformation, opt => opt.MapFrom(x => x.AppUserCompanySettings.Select(y => y.CompanySettings).ToList()))
CreateMap<CompanySetting, CompanySettingDto>();
}
}
I am writing an API call to get all companies that are linked to a specific UserId.
public async Task<IEnumerable<MemberDto>> GetCompaniesByUserIdAsync(int userId)
{
return await _context.Users
.Where(x => x.Id == userId)
.ProjectTo<MemberDto>(_mapper.ConfigurationProvider)
.ToListAsync();
}

Related

Receiving AutoMapperMappingException

Currently I'm creating a new feature. It looks simple, but I am stuck at a problem with automapping dto to another one.
I have to create a wishlist [adding /deleting items of wishlist].
All works fine, except one thing: while adding an item to the wishlist, I'm get a message like this:
"type": "AutoMapperMappingException",
"message": "Error mapping types..."
However, I can see it got inserted into the database. Also, can delete it too. I understand the problem is linked to Automapper, but I could not figure out how to map correctly.
[HttpPost]
public async Task<IActionResult> Add(WishListItemCreationDto wishListItemDto)
{
var itemAdd = _mapper.Map<WishlistItemDto>(wishListItemDto);
var itemCreated = await _wishListItemService.AddAsync(itemAdd);
return CreatedAtAction(nameof(GetId), new { id = itemCreated.Id }, wishListItemDto);
}
//service
public async Task<WishlistItemDto> AddAsync(WishlistItemDto item)
{
var entity = _mapper.Map<WishlistItem>(item);
var entityDetails = await _productDetailsRepository.GetById(item.ProductDetailId);
entity.ProductDetails = entityDetails;
await _wishListItemRepository.AddAsync(entity);
return _mapper.Map<WishlistItemDto>(entity);
}
DTOs:
public class WishListItemCreationDto
{
[Required]
public string CustomerId { get; set; }
[Required]
public int ProductDetailId { get; set; }
[Min(1)]
[Required]
public int Quantity { get; set; }
}
public class WishlistItemDto
{
public int Id { get; set; }
public string CustomerId { get; set; }
public int ProductDetailId { get; set; }
public ProductDetailsDtoWithPrimaryImage ProductDetails { get; set; }
public int Quantity { get; set; }
}
public class WishlistItem
{
public int Id { get; set; }
public string CustomerId { get; set; }
public Customer Customer { get; set; }
public int ProductDetailsId { get; set; }
public ProductDetails ProductDetails { get; set; }
public int Quantity { get; set; }
}
ProductDetails DTO:
public class ProductDetails
{
public int Id { get; set; }
public int ProductId { get; set; }
public Product Product { get; set; }
public IList<ProductAttributeValue> ProductAttributes { get; set; } = new List<ProductAttributeValue>();
public int Quantity { get; set; }
public string Sku => $"BRD{Id}";
public byte[] RowVersion { get; set; } = new byte[0];
}
public class ProductDetailsDtoWithPrimaryImage
{
public int Id { get; set; }
public int Quantity { get; set; }
public int ProductId { get; set; }
public ProductDisplayEntity Product { get; set; }
public IEnumerable<ProductAttributeWithValueDto> ProductAttributes { get; set; }
public byte[] RowVersion { get; set; }
public string Sku => $"BRD{Id}";
public int? PrimaryImageId { get; set; }
}
AutoMapper:
public WishlistItemProfile()
{
CreateMap<WishlistItem, WishListItemCreationDto>().ReverseMap();
CreateMap<WishlistItemDto, WishListItemCreationDto>().ReverseMap();
CreateMap<WishlistItem, WishlistItemDto>()
.ForMember(wi => wi.ProductDetailId, opt => opt.MapFrom(f => f.ProductDetailsId))
.ForMember(wi => wi.ProductDetails, opt => opt.MapFrom(f => f.ProductDetails))
.ReverseMap();
}
everything is okay, but you missed inner mapping of your classes.
What the error says:
Mapping types:
ProductDetailsDtoWithPrimaryImage -> ProductDetails
SimpleWebApi.Controllers.ProductDetailsDtoWithPrimaryImage -> SimpleWebApi.Controllers.ProductDetails
Add additional mapping in your constructor WishlistItemProfile
CreateMap<ProductDetails, ProductDetailsDtoWithPrimaryImage>().ReverseMap();
And it starts works perfect

How to Create EF one-to-one relationship with Asp.net Identity

Goal: Create a one-to-one relationship between EF Asp.Net.Identity.User and EF UserBusiness
This is my EF Asp.Net.Identity.User:
public class UserEntity:IdentityUser
{
public override string Id { get; set; }
public override string UserName { get; set; }
public override string Email { get; set; }
public override string NormalizedUserName { get; set; }
public override string NormalizedEmail { get; set; }
public string Telephone { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string MiddleName { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string ZipCode { get; set; }
public string Country { get; set; }
public DateTime? DateOfBirth { get; set; }
public string NIF { get; set; }
public string Gender { get; set; }
public string Password { get; set; }
public bool IsUserProfileCompleted { get; set; }
**public ICollection<UserBusinessEntity> Business { get; set; }**
public ICollection<PatientEntity> Patients { get; set; }
public DateTime UpdatedOn { get; set; }
public bool IsDeleted { get; set; }
public DateTime CreatedOn { get; set; }
My EF UserBusiness:
[Table ("UserBusiness")]
public class UserBusinessEntity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public string BusinessId { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string ZipCode { get; set; }
public string Country { get; set; }
public string Telephone { get; set; }
public string Email { get; set; }
public string Fax { get; set; }
public string Owner { get; set; }
public string OwnerPointofContact { get; set; }
public DateTime CreatedOn { get; set; }
public DateTime DeletedOn { get; set; }
public DateTime UpdatedOn { get; set; }
[ForeignKey("Id")]
public string Id { get; set; }
public virtual UserEntity User { get; set; }
}
Repository:
==> RepositoryExtension:
public static IQueryable<UserEntity> BuildUserWithBusiness(this IQueryable<UserEntity> query)
{
return query.Include(u => u.Business);
}
==> Repository
public async Task<UserEntity> GetByIdWithBusinessAsync(string businessId)
{
return await _context.Users
.BuildUserWithBusiness()
.FirstOrDefaultAsync(x => x.Id == businessId);
}
Fluent API:
public class DentalClinicDbContext : IdentityDbContext<UserEntity, UserRoleEntity, string>
{
public DbSet<UserBusinessEntity> UserBusiness { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<UserEntity>(entity =>
{
entity.ToTable("Users");
});
builder.Entity<UserEntity>(entity =>
{
entity.HasOne(b => b.Business)
.WithOne(u => u.User);
});
I got an error on u.User
Error:
'ICollection' does not contain a definition for 'User' and no accessible extension method 'User' accepting a first argument of type 'Collection could be found (are you missing a using directive or an assembly reference?)
There is a line in your code,
public ICollection<UserBusinessEntity> Business { get; set; }
which should be changed to,
public UserBusinessEntity Business { get; set; }
Also, the model builder should be changed to,
builder.Entity<UserEntity>(entity =>
{
entity.HasOne(b => b.Business)
.WithOne(u => u.User);
.HasForeignKey<BusinessUser>(c => c.Id);
});
Please note that I haven't tried the code real-time.
You should follow this example:
https://www.entityframeworktutorial.net/efcore/configure-one-to-one-relationship-using-fluent-api-in-ef-core.aspx

How to order by ascending in ASP.NET?

I want to sort by Module Code. I tried adding OrderBy(m => m.code) but the error says 'does not contain a definition for 'OrderBy'...'.
public async Task<IEnumerable<Module>> GetAllModules()
{
return await context.Modules
.Include(m => m.Lecturers)
.ThenInclude(ml => ml.Lecturer)
.ToListAsync();
}
Module class:
public class Module
{
public int Id { get; set; }
public string Name { get; set; }
public string Code { get; set; }
public ICollection<ModuleLecturer> Lecturers { get; set; }
public Module()
{
Lecturers = new Collection<ModuleLecturer>();
}
}
ModuleLecturer class:
public class ModuleLecturer
{
public int ModuleId { get; set; }
public int LecturerId { get; set; }
public Module Module { get; set; }
public Lecturer Lecturer { get; set; }
}
Lecturer class:
public class Lecturer
{
public int Id { get; set; }
public string Name { get; set; }
public string Title { get; set; }
}

Code First Model Definition

I have the following models,do I define it Ok?
User is the main Entity and can have 0..1 to * (zero /one to many relationship ) address.
2.User can have have 0..1 to 1 (one to one userPass )
This is the main table
public class User
{
[Key]
[Required]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public string UserId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
public string PhoneWork { get; set; }
public string WorkingAt { get; set; }
public virtual UserPass UserPass { get; set; }
public virtual ICollection<Address> Addresses { get; set; }
}
public class ConfigModelDbContext : DbContext
{
public DbSet<User> User { get; set; }
public DbSet<Address> Addresses { get; set; }
public DbSet<UserPass> UserPasses { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Entity<User>()
.HasOptional(c => c.Addresses).WithRequired(addresses => new User());
modelBuilder.Entity<User>()
.HasOptional(c => c.UserPass).WithRequired(pass => new User());
}
}
Address Class
public class Address
{
[Key]
[ForeignKey("User")]
public string UserId { get; set; }
public string UserAddress { get; set; }
}
Userpass class
public class UserPass
{
[Key]
[ForeignKey("User")]
public string UserId { get; set; }
public string User { get; set; }
public string Password { get; set; }
}
i also created classes same as above but can it create relationship directly on database table?
at first I offer you to use data annotation instead of fluent api always.
then correct AddressClass like below:
public class Address
{
[Key]
public int Id { get; set; }
[ForeignKey("UserId")]
public User User { get; set; }
public string UserId { get; set; }
public string UserAddress { get; set; }
}
This will create Ralationship.
for more details please read Code First DataAnnotations

ASP.NET MVC 4 Code First Many to Many Adding to Collection

I am using ASP.NET MVC 4 code first pattern for database layer. I have a many to many relationship between UserProfile and Task. When I try to add a task to the the collection of tasks of a user, it's added but if I try to query it and see if it's there it's not showing up.
My model:
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
public string FirstName { get; set; }
public string SirName { get; set; }
public string Position { get; set; }
public string Email { get; set; }
public ICollection<TaskModels> Tasks {get; set; }
public bool? isActive { get; set; }
public UserProfile()
{
Tasks = new HashSet<TaskModels>();
}
}
public class TaskModels
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public DateTime? StartDate { get; set; }
public DateTime? EndDate { get; set; }
public ICollection<UserProfile> Employees { get; set; }
public int TimeNeeded { get; set; }
public int TimeWorked { get; set; }
public string Status { get; set; }
public bool isActive { get; set; }
public TaskModels()
{
Employees = new HashSet<UserProfile>();
}
}
public class WorkLogModels
{
public int Id { get; set; }
public UserProfile Author { get; set; }
public DateTime TimeBeganWorking { get; set; }
public int TimeWorkedOn { get; set; }
public TaskModels Task { get; set; }
public string Description { get; set; }
}
public class TimeTrackerDb : DbContext
{
public TimeTrackerDb() : base("DefaultConnection")
{
}
public DbSet<UserProfile> UserProfiles { get; set; }
public DbSet<TaskModels> Tasks { get; set; }
public DbSet<WorkLogModels> WorkLogs { get; set; }
}
I try to check if a UserProfile already exists in a Task's Employees list and it's always empty.
[HttpPost]
public ActionResult Create(WorkLogModels worklogmodels)
{
var tasks = db.Tasks.Where(x => x.Name == worklogmodels.Task.Name).SingleOrDefault();
if (tasks == null)
{
return View(worklogmodels);
}
if (ModelState.IsValid)
{
var user = db.UserProfiles.Where(x => x.UserId == WebSecurity.CurrentUserId).FirstOrDefault();
var task = db.Tasks.Where(x => x.Name == worklogmodels.Task.Name).FirstOrDefault();
WorkLogModels log = new WorkLogModels();
log.Description = worklogmodels.Description;
log.TimeBeganWorking = worklogmodels.TimeBeganWorking;
log.TimeWorkedOn = worklogmodels.TimeWorkedOn;
log.Author = user;
log.Task = task;
db.WorkLogs.Add(log);
if (!db.UserProfiles.Where(x => x.UserId == WebSecurity.CurrentUserId).First().Tasks.Any(x=> x.Name == worklogmodels.Task.Name))
{
db.UserProfiles.Where(x => x.UserId == WebSecurity.CurrentUserId).FirstOrDefault().Tasks.Add(task);
db.Tasks.Where(x => x.Name == worklogmodels.Task.Name).FirstOrDefault().Employees.Add(user);
}
db.SaveChanges();
return RedirectToAction("Index");
}
return View(worklogmodels);
}
I've been fighting with this for two days now.
Any help will be greatly appreciated
EDIT:
I am not sure if I made myself clear. In the Crate action for the WorkLog Controller I am trying to put the current user in the current task's collection and vice versa. It works correctly the first time, but then if I do it again it fails to skip the if statement and tries to add it once again and throws an exception : System.Data.SqlClient.SqlException. It's trying to add the same record to the intermediate table.

Resources