I have the following entities in my solution
public class UtilityAccount : IObjectWithState
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid UtilityAccountID { get; set; }
public string Account { get; set; }
[ForeignKey("Person")]
public Guid PersonID { get; set; }
public virtual Person Person { get; set; }
public string ForeignID { get; set; }
[NotMapped]
public ObjectState ObjectState { get; set; }
public virtual ICollection<Utility> Utilities { get; set; }
public UtilityAccount()
{
Utilities = new List<Utility>();
}
}
public class Utility : IObjectWithState
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid UtilityID { get; set; }
[ForeignKey("UtilityAccount")]
public Guid UtilityAccountID { get; set; }
public virtual UtilityAccount UtilityAccount { get; set; }
public Guid? ServiceAddressID { get; set; }
[ForeignKey("ServiceAddressID")]
public virtual Address ServiceAddress { get; set; }
[NotMapped]
public ObjectState ObjectState { get; set; }
public double CurrentBalance { get; set; }
public double? PendingPaymentTotal { get; set; }
public string ForeignID { get; set; }
[ForeignKey("UtilityType")]
public Guid UtilityTypeID { get; set; }
public virtual UtilityType UtilityType { get; set; }
public virtual ICollection<UtilityBill> UtilityBills { get; set; }
public virtual ICollection<IncomingUtilityPayment> IncomingPayments { get; set; }
public Utility()
{
UtilityBills = new List<UtilityBill>();
IncomingPayments = new List<IncomingUtilityPayment>();
}
}
public class IncomingUtilityPayment : IObjectWithState
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid IncomingPaymentID { get; set; }
public string ForeignID { get; set; }
[ForeignKey("Utility")]
public Guid UtilityID { get; set; }
public virtual Utility Utility { get; set; }
public DateTime PaymentDate { get; set; }
public IncomingPaymentStatus IncomingPaymentStatus { get; set; }
public double? UtilityAmount { get; set; }
public double? ConvenienceFee { get; set; }
public double? TotalAmount { get; set; }
public string AuthCode { get; set; }
public string AuthReference { get; set; }
public string TenderType { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int PaymentIdent { get; set; }
[NotMapped]
public ObjectState ObjectState { get; set; }
}
My problem is that I am trying to use Linq to retrieve information about a UtilityAccount and I am running into issues with the IncomingPayments for a Utility. Below is the select statement I am trying to use.
returnVal = repo.AllIncluding(o => o.Person, o => o.Utilities, o => o.Utilities.Select(p => p.UtilityType), o => o.Person.BillingAddress, o => o.Utilities.Select(p => p.ServiceAddress), o => o.Utilities.Select(p => p.IncomingPayments.Where(q => q.IncomingPaymentStatus == IncomingPaymentStatus.Pending || q.IncomingPaymentStatus == IncomingPaymentStatus.Processed )));
Everything ran fine until I added this clause to the statement.
o => o.Utilities.Select(p => p.IncomingPayments.Where(q => q.IncomingPaymentStatus == IncomingPaymentStatus.Pending || q.IncomingPaymentStatus == IncomingPaymentStatus.Processed ))
I think my issue ends up being something I am writing wrong in my Linq clause. The error I am getting is
The Include path expression must refer to a navigation property defined on the type. Use dotted paths for reference navigation properties and the Select operator for collection navigation properties.
Parameter name: path
I can use the following statement with no issues
o => o.Utilities.Select(p => p.IncomingPayments)
as soon as I add the where clause in I get the error
I'm not familiar with EntityFramework nor linq-to-entities, but if it's just like linq-to-object you can:
add a .Where(p => p.IncomingPayments != null) before chaining with your .Select() like this
o.Utilities.Where(p => p.IncomingPayments != null)
.Select(p => p.IncomingPayments.Where(q => q.IncomingPaymentStatus == IncomingPaymentStatus.Pending || q.IncomingPaymentStatus == IncomingPaymentStatus.Processed))
The result will be a nested IEnumerable, i.e. IEnumerable<IEnumerable<IncomingUtilityPayment>>
If you actually need a IEnumerable<IncomingUtilityPayment> then .SelectMany() come in to play.
o.Utilities.Where(p => p.IncomingPayments != null)
.SelectMany(p => p.IncomingPayments)
.Where(q => q.IncomingPaymentStatus == IncomingPaymentStatus.Pending || q.IncomingPaymentStatus == IncomingPaymentStatus.Processed)
Hope this help
Related
I'm having trouble finding recipes that contain all of selected ingredients.
Models:
Recipe
public int Id { get; set; }
[StringLength(64)]
public string Name { get; set; }
public string Description { get; set; }
[StringLength(256)]
public string CoverURL { get; set; }
public int PreparationTime { get; set; }
public DateTime AddedDate { get; set; }
public RecipeCategory Category { get; set; }
public List<RecipeImage> Images { get; set; }
public List<RecipeIngredient> Ingredients { get; set; }
public List<RecipeSpice> Spices { get; set; }
Ingredient
public int Id { get; set; }
[StringLength(64)]
public string Name { get; set; }
public List<RecipeIngredient> Recipes { get; set; }
[NotMapped]
public bool IsSelected { get; set; }
RecipeIngredient
public int Id { get; set; }
public double Quantity { get; set; }
public Unit Unit { get; set; }
public Recipe Recipe { get; set; }
public Ingredient Ingredient { get; set; }
And I tried
List<Ingredient> selectedIngredients = new List<Ingredient>();
selectedIngredients = _vm.Ingredients.Select(x => x).Where(x => x.IsSelected).ToList();
List<Recipe> recipes = new List<Recipe>();
recipes = _vm.Recipes.Where(x => selectedIngredients.Contains(x.Ingredients));
But it return a error:
cannot convert from
'System.Collections.Generic.List<RecipeApp.Model.RecipeIngredient>' to
'RecipeApp.Model.Ingredient'
I know it's a problem becouse "selectedIngredients" is a List of Ingredients, and a "x.Ingredients" is a list of RecipeIngredients. But I can't do it properly.
I did it, but maybe someone will do it better?
List<Recipe> recipes = new List<Recipe>();
List<Ingredient> selectedIngredients = new List<Ingredient>();
selectedIngredients = _vm.Ingredients.Select(x => x).Where(x => x.IsSelected).ToList();
var recipeIngredients = _vm.Recipes.Select(r => r.Ingredients).ToList();
foreach(var ingredientsList in recipeIngredients)
{
var recipe = ingredientsList.Select(x => x.Recipe)
.Where(u => ingredientsList
.Select(l => l.Ingredient.Id)
.Intersect(selectedIngredients
.Select(l2 => l2.Id))
.Contains(u.Id))
.FirstOrDefault();
if (recipe != null)
recipes.Add(recipe);
how do I query this many to many relationship? I am starting with ACCOUNT, and want to return the ExecutingBroker.Firm associated with it.
I am starting with Account, then I guess drill to MANAGER, then to MAPPING_MANAGER, then to EXECUTINGBROKER.
Here is my query so far...
var student = dbEF.Accounts
.Where(x => x.AccountNumber == acctNum)
.Select(x => new DTOCrmDetails()
{
AccountNumber = x.AccountNumber,
AccountName = x.AccountName,
DateOpened = x.DateOpened,
CommissionId = x.CommissionId,
Commission = x.Commission,
ManagerID = x.ManagerID,
ManagerName = x.Manager.ManagerName,
Manager = x.Manager,
Employees = x.Manager.Employees,
WireInstructionsUSD = x.Manager.WireInstructionsUSDs
}).FirstOrDefault();
below is the code that was generated from ef from existing database.
public partial class Manager
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Manager()
{
this.Accounts = new HashSet<Account>();
this.Employees = new HashSet<Employee>();
this.WireInstructionsUSDs = new HashSet<WireInstructionsUSD>();
this.Mapping_ManagersExecutingBrokers = new HashSet<Mapping_ManagersExecutingBrokers>();
}
public int ManagerID { get; set; }
public string ManagerName { get; set; }
public string Strategy { get; set; }
public string ManagerShortCode { get; set; }
public Nullable<int> WireInstructionsUsdID { get; set; }
public Nullable<int> WireInstructionsForeignID { get; set; }
public string MEtradingPlatform { get; set; }
public string EtradingCostResp { get; set; }
public string NotesManager { get; set; }
public bool MainStrategy { get; set; }
public string PathPayments { get; set; }
public string PathEtrading { get; set; }
public string LEI { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Account> Accounts { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Employee> Employees { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<WireInstructionsUSD> WireInstructionsUSDs { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Mapping_ManagersExecutingBrokers> Mapping_ManagersExecutingBrokers { get; set; }
}
}
{
using System;
using System.Collections.Generic;
public partial class Mapping_ManagersExecutingBrokers
{
public int Mapping_ManagersExecutingBrokersId { get; set; }
public Nullable<int> ManagerID { get; set; }
public Nullable<int> ExecutingBrokersId { get; set; }
public virtual ExecutingBroker ExecutingBroker { get; set; }
public virtual Manager Manager { get; set; }
}
}
public partial class ExecutingBroker
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public ExecutingBroker()
{
this.Mapping_ManagersExecutingBrokers = new HashSet<Mapping_ManagersExecutingBrokers>();
}
public int ExecutingBrokersId { get; set; }
public string Firm { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Mapping_ManagersExecutingBrokers> Mapping_ManagersExecutingBrokers { get; set; }
}
You have to go through Mapping_ManagersExecutingBrokers, since you've modelled it that way.
Keep in mind that you have a collection of Firms, since it's a many-to-many-relationship.
.Select(account => new { Firms = account.Manager.Mapping_ManagersExecutingBrokers
.Select(meb => meb.ExecutingBroker.Firm) });
I am use code first model with a relationship below
public class ApplicationUser : IdentityUser
{
public string UserFirstName { get; set; }
public string UserLastName { get; set; }
public string UserSchool { get; set; }
public UserProfileData UserProfileData { get; set; }
public int? MedicalSpecialtyId { get; set; }
public virtual MedicalSpecialty MedicalSpecialty { get; set; }
// public int? AnalyticsDataId { get; set; }
// public ICollection<AnalyticsData> AnalyticsDatas { get; set; }
}
public class MedicalSpecialty
{
public int Id { get; set; }
public string Description { get; set; }
// public int ApplicationUserId { get; set; }
public virtual ApplicationUser ApplicationUser { get; set; }
public ICollection<ProgramDetailData> ProgramDetailDatas { get; set; }
}
And when I try to get a User's associated MedicalSpecialty object it is NULL
userSpecialtyName = currentUser.MedicalSpecialty.Description;
BUT when I run this code above it the currentUser.MedicalSpecialty is no longer NULL. What happened?? Somehow that LINQ query woke up the object and filled it with data
var userSpecialtyId = currentUser.MedicalSpecialtyId;
userSpecialtyName = _medicalSpecialtyRepository.Find
(x => x.Id == userSpecialtyId).FirstOrDefault().Description;
userSpecialtyName = currentUser.MedicalSpecialty.Description;
i have a class like this
public class Survey
{
public Survey()
{
SurveyResponses=new List<SurveyResponse>();
}
public Guid SurveyId { get; set; }
public string SurveyName { get; set; }
public string SurveyDescription { get; set; }
public virtual ICollection<Question> Questions { get; set; }
public virtual ICollection<SurveyResponse> SurveyResponses { get; set; }
}
and a Question class like this
public class Question
{
public Guid QuestionId { get; set; }
public string QuestionText { get; set; }
public QuestionType QuestionType { get; set; }
public virtual ICollection<Option> Options { get; set; }
public bool IsOtherAllowed { get; set; }
public virtual ICollection<Answer> Answers { get; set; }
}
i want to write a query to select a survey which contains a particular question
something along these lines
Survey s1 = db.Surveys.Where(s => s.Questions.Where(q => q.QuestionId == "1eb56610-853d-4a9e-adc7-e0ec069390b7"));
Survey s1 = db.Surveys
.Where(s => s.Questions.Any(q => q.QuestionId == "1eb56610-853d-4a9e-adc7-e0ec069390b7"))
.FirstOrDefault();
I have two rows of test data and am able to pull back the first row with no problems but can't get the second row to return. Digging around and testing shows that this is probably due to the AppovedByID column being null in the row that is not being returned. I have looked but can't figure out how to modify my LINQ query so it will return all rows even if the child table can't be linked in due to a null value.
The Query:
public JsonResult ChangeOrders()
{
var ChangeOrdersList = _DbContext.ChangeOrders
.Include(co => co.ApprovalStatus)
.Include(co => co.ApprovedBy)
.Include(co => co.AssignedTo)
.Include(co => co.CreatedBy)
.Include(co => co.CurrentStatus)
.Include(co => co.Impact)
.Include(co => co.Priority)
.Include(co => co.ChangeType)
.Select(co => new ChangeOrderListVM()
{
ApprovalStatus = co.ApprovalStatus.Name,
ApprovedBy = string.Concat(co.ApprovedBy.FirstName, ' ', co.ApprovedBy.LastName),
AssignedTo = string.Concat(co.AssignedTo.FirstName, ' ', co.AssignedTo.LastName),
CreatedBy = string.Concat(co.CreatedBy.FirstName, ' ', co.CreatedBy.LastName),
CurrentStatus = co.CurrentStatus.Name,
DateApproved = co.DateApproved,
DateCompleated = co.DateCompleated,
DateCreated = co.DateCreated,
DateStarted = co.DateStarted,
EstimatedEndDate = co.EstimatedEndDate,
EstimatedStartDate = co.EstimatedStartDate,
ID = co.ID,
Impact = co.Impact.Name,
Name = co.Name,
Priority = co.Priority.Name,
Reason = co.ReasonForChange,
Type = co.ChangeType.Name
}).ToList();
return Json(ChangeOrdersList);
}
ChangeOrders:
public class ChangeOrder
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
public short? ApprovedByUserID { get; set; }
public byte ApprovalStatusID { get; set; }
public short AssignedToUserID { get; set; }
public short CreatedByUserID { get; set; }
public byte CurrentStatusID { get; set; }
public DateTime? DateApproved { get; set; }
public DateTime? DateCompleated { get; set; }
public DateTime DateCreated { get; set; }
public DateTime? DateStarted { get; set; }
public DateTime EstimatedStartDate { get; set; }
public DateTime EstimatedEndDate { get; set; }
public byte ImpactID { get; set; }
public byte PriorityID { get; set; }
public byte TypeID { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string ReasonForChange { get; set; }
[ForeignKey("ApprovalStatusID")]
public ChangeApprovalStatus ApprovalStatus { get; set; }
[ForeignKey("ApprovedByUserID")]
public User ApprovedBy { get; set; }
[ForeignKey("AssignedToUserID")]
public User AssignedTo { get; set; }
[ForeignKey("CreatedByUserID")]
public User CreatedBy { get; set; }
[ForeignKey("CurrentStatusID")]
public ChangeStatus CurrentStatus { get; set; }
[ForeignKey("ImpactID")]
public ChangeImpact Impact { get; set; }
[ForeignKey("PriorityID")]
public ChangePriority Priority { get; set; }
[ForeignKey("TypeID")]
public ChangeType ChangeType { get; set; }
}
Users:
public class User
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public short ID { get; set; }
[Required]
public string ADUserName { get; set; }
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
[Required]
public string Email { get; set; }
[Required]
public string Phone { get; set; }
[Required]
public DateTime LastUpdated { get; set; }
}
EDIT:
This is apparently unique to Entity Framework 7 (AKA Core) as it works fine in EF 6. I am in fact using EF7 and as an additional test I updated a single line
ApprovedBy = string.Concat(co.ApprovedBy.FirstName, ' ', co.ApprovedBy.LastName),
and changed it to this
ApprovedBy = "",
and all the rows are returning so I then tried to do
ApprovedBy = (co.ApprovedByUserID.HasValue) ? string.Concat(co.ApprovedBy.FirstName, ' ', co.ApprovedBy.LastName) : "",
but that give a very odd error:
incorrect syntax near the keyword 'is'
This is a bug in the library. I have reported the bug for fixing in the next version on github