Statement doesn't return all entities - c#

I'm calling a linq statement that doesn't appear to be working correctly:
My Client Model:
public class Client
{
[UIHint("Hidden")]
public int ClientId { get; set; }
[UIHint("Hidden")]
public int UserProfileId { get; set; }
public int Age { get; set; }
[UIHint("Hidden")]
public int GenderId { get; set; }
public string GenderDescription { get; set; }
[UIHint("Hidden")]
public int SettingId { get; set; }
public virtual Gender Gender { get; set; }
public virtual Setting Setting { get; set; }
public virtual UserProfile UserProfile { get; set; }
}
My Linq Call:
var clients = db.Clients.Include(c => c.Gender).Include(c => c.Setting).Include(c => c.UserProfile).OrderBy(c => c.ClientId);
This will populate both the Gender and Setting fields with the proper info based off of the GenderId and SettingId, but the UserProfile does not. Is there a rational explanation or do I need to keep beating my head against the desk?

The problem that I had was that when I created the UserProfile Model I used UserId instead of UserProfileId. The framework kept looking for an Id that did not exist.
The proper model should look like this:
public class UserProfile
{
public UserProfile()
{
this.Casefiles = new HashSet<Casefile>();
}
[Display(Name="Author")]
public string FullName
{
get { return LastName + ", " + FirstName; }
}
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserProfileId { get; set; }
public string UserName { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
[EmailAddress]
public string EmailAddress { get; set; }
// UserInRole Level
public string Role { get; set; }
[Display(Name = "Request Account Uplevel to Contributor")]
public bool RequestUplevel { get; set; }
public virtual ICollection<Casefile> Casefiles { get; set; }
}
This way when you make a call like:
var clients = db.Clients.Include(c => c.Gender)
.Include(c => c.Setting)
.Include(c => c.UserProfile)
.OrderBy(c => c.ClientId)
.Where(u => u.UserProfileId == WebSecurity.CurrentUserId);
This will return each of the virtual calls in the Client Model.

Related

How to get data from child to parent entity framework core?

I have two table like this -
public class Job
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime AddedTime { get; set; } = DateTime.Now;
public DateTime LastEdit { get; set; } = DateTime.Now;
public string Explanation { get; set; }
public string PhotoString { get; set; }
public bool isActive { get; set; } = true;
public int CompanyId { get; set; }
public Company Company { get; set; }
}
and company -
public class Company
{
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string Explanation { get; set; }
public string Email { get; set; }
public string PhoneNumber { get; set; }
public string PhotoString { get; set; }
public bool isActive { get; set; } = true;
public int AppUserId { get; set; }
public AppUser AppUser { get; set; }
public List<Job> Jobs { get; set; }
}
I only want to get AppUserId from Company and all Jobs from every Company. I tried this and it gave me error.
using var context = new SocialWorldDbContext();
return await context.Jobs.Where(I => I.isActive == true && I.Company.isActive).Include(I=>I.Company.AppUserId).ToListAsync();
So my question is there any way I can get this data from parent?
Include adds whole entities to the output. To add just one property use Select, something like
context.Jobs
.Where(I => I.isActive == true && I.Company.isActive)
.Select(e => new {Job=e, CompanyAppUserId = e.Company.AppUserId})
.ToListAsync();

What is the query to access a data with the foreign key within Entity Framework?

I want to list the data of the table sale, accessing the name of the user with the foreign key userId, what is the correct way to do this with the context?
using (var context = new AppDbContext())
{
var comic = context.sale.Select(d => d);
}
public class sale
{
public int saleId { get; set; }
public DateTime date { get; set; }
public int userId { get; set; }
}
public class user
{
public int userId { get; set; }
public string name { get; set; }
public string surname { get; set; }
public string email { get; set; }
public string password { get; set; }
}
Context:
modelBuilder.Entity<sale>()
.HasOne<user>()
.WithMany()
.HasForeignKey(p => p.userId);
You need to alter you classes to add navigation properties:
public class sale
{
public int saleId { get; set; }
public DateTime date { get; set; }
public int userId { get; set; }
public user user { get; set; }
}
public class user
{
public int userId { get; set; }
public string name { get; set; }
public string surname { get; set; }
public string email { get; set; }
public string password { get; set; }
public ICollection<sale> sales { get; set; } = new HashSet<sale>();
};
Then change your context:
modelBuilder.Entity<sale>()
.HasOne(a => a.user)
.WithMany(a => a.sales)
.HasForeignKey(p => p.userId);
You can then get the related data with:
var user = context.sale.Include(a => a.user)...

Include in EF C#

I have three tables:
Member, business and business address
I'm able to fetch the business with member using Include, but I'm trying to get businessAddress, it is asking for direct relationship i guess.
Here is my models:
[Table("member")]
public partial class Member
{
public Member()
{
Business = new HashSet<Business>();
// BusinessAddress = new HashSet<BusinessAddress>();
}
[Key]
public int memberId { get; set; }
public int chapterid { get; set; }
public string title { get; set; }
public string firstname { get; set; }
public string lastname { get; set; }
public bool IsActive { get; set; }
public string classification { get; set; }
public int SortOrder { get; set; }
public virtual ICollection<Business> Business { get; set; }
// public virtual ICollection<BusinessAddress> BusinessAddress { get; set; }
}
Business
[Table("Business")]
public partial class Business
{
public Business()
{
BusinessAddress = new HashSet<BusinessAddress>();
}
[Key]
public int BusinessID { get; set; }
public int? categoryid { get; set; }
public int? subcategoryid { get; set; }
public int memberid { get; set; }
public string businessname { get; set; }
public string dealingin { get; set; }
public int? sortOrder { get; set; }
[ForeignKey("memberid")]
public Member Member { get; set; }
public ICollection<BusinessAddress> BusinessAddress { get; set; }
}
BusinessAddress
[Table("BusinessAddress")]
public partial class BusinessAddress
{
[Key]
public int businessaddressid { get; set; }
public int businessid { get; set; }
[ForeignKey("businessid")]
public virtual Business Business { get; set; }
public string address { get; set; }
}
Below is my EF query:
var list = _dbContext.Member.Include("Business").OrderByDescending(x => x.SortOrder).ThenBy(x => x.firstname).ToList();
I want to get Member with business and BusinessAddresses. I have tried Include("BusinesADdress") that didn't work, Help me please.
Try using Include accepting lambda selector followed by ThenInclude:
var list = _dbContext.Member
.Include(m => m.Business)
.ThenInclude(b => b.BusinessAddress)
.OrderByDescending(x => x.SortOrder)
.ThenBy(x => x.firstname)
.ToList();
Also you can just append all needed relations via . in the Include call but in general I would recommend against it cause the first approach is type safe:
var list = _dbContext.Member
.Include("Business.BusinessAddress")
.OrderByDescending(x => x.SortOrder)
.ThenBy(x => x.firstname)
.ToList();

Updating entity tree with deep nested entities

My app deals with saving orders received from an external system. The order contains child items like line items, address, fulfillments, refunds > refund items etc.
Currently, I use an ugly looking code to detect what has changed in each entity by its External Id. Can someone recommend me a better way? :)
Following is a simplified entity model of Order
public class Order
{
public long Id { get; set; }
public string ExternalOrderId { get; set; }
public List<LineItem> LineItems { get; set; }
public List<Fulfillment> Fulfillments { get; set; }
public ShippingAddress ShippingAddress { get; set; }
public List<Refund> Refunds { get; set; }
public string FinancialStatus { get; set; }
public string FulfillmentStatus { get; set; }
}
public class LineItem
{
public long Id { get; set; }
public string ExternalLineItemId { get; set; }
public string SKU { get; set; }
public int Quantity { get; set; }
public long OrderId { get; set; }
}
public class Fulfillment
{
public long Id { get; set; }
public string ExternalFulfillmentId { get; set; }
public string Status { get; set; }
public string TrackingUrl { get; set; }
public long OrderId { get; set; }
}
public class ShippingAddress
{
public long Id { get; set; }
public string ExternalShippingAddressrId { get; set; }
public string Addres { get; set; }
public long OrderId { get; set; }
}
public class Refund
{
public long Id { get; set; }
public string ExternalRefundId { get; set; }
public List<RefundedItem> LineItems { get; set; }
public string CancelledReason { get; set; }
public long OrderId { get; set; }
}
public class RefundedItem
{
public long Id { get; set; }
public string ExternalRefundedItemId { get; set; }
public string SKU { get; set; }
public int Quantity { get; set; }
}
My sample code:
private async Task ManageFulfillments(long orderId, Order order)
{
if (order.Fulfillments == null || !order.Fulfillments.Any()) return;
var newFulfillmentIds = order.Fulfillments.Select(c => c.ExternalFulfillmentId).ToList();
var dbFulfillments = await _fulfillmentRepository.GetAll().IgnoreQueryFilters()
.Where(c => c.OrderId == orderId)
.Select(c => new { c.Id, c.ExternalFulfillmentId }).ToListAsync();
var dbFulfillmentIds = dbFulfillments.Select(c => c.ExternalFulfillmentId).ToList();
// Delete Fulfillments that are not present in new Fulfillments list
var deletedFulfillments = dbFulfillmentIds.Except(newFulfillmentIds).ToList();
if (deletedFulfillments.Any())
{
await _fulfillmentRepository.DeleteAsync(c =>
deletedFulfillments.Contains(c.ExternalFulfillmentId) && c.ExternalOrderId == orderId);
}
// Update existing Fulfillments ids
order.Fulfillments
.Where(c => dbFulfillmentIds.Contains(c.ExternalFulfillmentId))
.ToList()
.ForEach(async c =>
{
c.Id = dbFulfillments.Where(p => p.ExternalFulfillmentId == c.ExternalFulfillmentId)
.Select(p => p.Id).FirstOrDefault();
await _fulfillmentRepository.UpdateAsync(c);
});
// New Fulfillments will automatically be added by EF
}
I have similar code in place to update other entites as well and I'm not proud of it!

Patching the properties of a children entity. How to correctly map the entity to execute the patch method

I have created a patch method in my ClientUserController but the patchDoc is not updating the properties of the User entity which is a child of ClientUser entity. The Post method is working fine and it's updating every child property of the ClientUser entity which I have mapped. However, for some reason this is not working for the PATCH method.
User
public int Id { get; set; }
public Genders Gender { get; set; }
[MaxLength(30)]
public string FirstName { get; set; }
[MaxLength(30)]
public string LastName { get; set; }
public DateTime BirthDay { get; set; }
[EmailAddress]
public string Email { get; set; }
[Phone]
public string Phone { get; set; }
public string Address { get; set; }
[ForeignKey("CityId")]
public City City { get; set; }
public int CityId { get; set; }
ClientUser
public int Id { get; set; }
[ForeignKey("UserId")]
public User User { get; set; }
public int UserId { get; set; }
[EmailAddress]
public string Email { get; set; }
[Phone]
[MaxLength(15)]
public string Phone { get; set; }
[ForeignKey("DepartmentId")]
public Department Department { get; set; }
public int DepartmentId { get; set; }
public string JobTitle { get; set; }
[ForeignKey("ClientId")]
public Client Client { get; set; }
public int ClientId { get; set; }
ClientUserController (simple)
[HttpPatch("{id}", Name = "PatchClientUser")]
public async Task<IActionResult> PatchClientUser(int clientId, int id,
[FromBody] JsonPatchDocument<ClientUserForUpdateDto> patchDoc)
{
if (patchDoc == null)
{
return BadRequest();
}
var clientUserFromRepo = await _clientUserRepository.GetClientUserByIdAsync(clientId, id);
if (clientUserFromRepo == null)
{
return NotFound("Client User Not Found");
}
var clientUserToPatch = Mapper.Map<ClientUserForUpdateDto>(clientUserFromRepo);
patchDoc.ApplyTo(clientUserToPatch);
Mapper.Map(clientUserToPatch, clientUserFromRepo);
_clientUserRepository.UpdateEntity(clientUserFromRepo);
await _clientUserRepository.SaveChangesAsync();
return NoContent();
}
ClientUserProfile
public class ClientUserProfile : Profile
{
public ClientUserProfile()
{
CreateMap<ClientUser, ClientUserDto>();
CreateMap<ClientUserForCreationDto, ClientUser>();
CreateMap<ClientUser, ClientUserForUpdateDto>(MemberList.Destination);
CreateMap<ClientUserForUpdateDto, ClientUser>(MemberList.Source);
}
UserProfile
public class UserProfile : Profile
{
public UserProfile()
{
CreateMap<User, UserDto>();
CreateMap<UserForCreationDto, User>();
CreateMap<User, UserForUpdateDto>(MemberList.Destination);
CreateMap<UserForUpdateDto, User>(MemberList.Source);
}
}
The POST method as well as the GET method for a ClientUser is working properly.
My ClientUserForUpdateDto looks as follow:
public string UserFirstname { get; set; }
public string UserLastname { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
public int DepartmentId { get; set; }
public string JobTitle { get; set; }
in my requestBody from postman I have the following:
[
{
"op": "replace",
"path": "/userLastname",
"value": "Some lastname"
}
]
Which would be the way to go if I want to change the LastName of a clientUser by its Id and map it correctly.
In Postman as a response I get the correct NoContent response. However, the ClientUser is not updated.
You problem should be in the following code line :
Mapper.Map(clientUserToPatch, clientUserFromRepo);
You could add the following code in your ClientUserProfile :
CreateMap<ClientUserForUpdateDto, ClientUser>(MemberList.Source)
.ForMember(dest=>dest.User , opt => opt.MapFrom(src => src));
CreateMap<ClientUserForUpdateDto, User>()
.ForMember(dest => dest.LastName, opt => opt.MapFrom(src => src.UserLastname))
.ForMember(dest => dest.FirstName, opt => opt.MapFrom(src => src.UserFirstname));

Categories

Resources