I am facing a problem as discussed below.
I have four tables
PateintTable
PatientRecordTable(FK=PatientID)
RecordMedicineTable(FK=MedicineID,RecordID)
MedicineTable
I want to get a specific Patient data depending upon the PatientID of the patient along with the patient data, I want to obtain his medical-records (PatientRecordTable) plus medicines associated with each of his records.
I tried many tricks but exceptions occur when I try to get the medicines.
lstPrescribedMedicines.Items.Clear();
foreach (var item in result.RecordsMedicines)
{
lstPrescribedMedicines.Items.Add(item.Medicine.MedName);
}
I am implementing using(context=new mss-context()).
This is my query:
var pateintRecords = context
.PateintRecords
.Include(p => p.Patient)
.Include(m=>m.RecordsMedicines)
.Where(x => x.PatientID == pateintID).ToList();// as IQueryable;
When working with children of children, you have to include them:
var pateintRecords = context
.PateintRecords
.Include(p => p.Patient)
.Include(m=>m.RecordsMedicines)
.Include(m=>m.RecordsMedicines.Select(i => i.Items))
.Where(x => x.PatientID == pateintID).ToList();// as IQueryable;
Related
My models structure looks like this:
UserProgresses:dbset
LessonProgresses:List // The lesson progress a user has in one course
Lesson:Lesson // The general Lesson class.
Materials:List // A list of lesson materials
When I execute this query:
var progresses = context.UserProgresses
.Include(x => x.LessonProgresses.Select(y => y.Lesson.Materials))
.SingleOrDefault(x => x.Id == progressId);
This is the result I get after executing that query:
foreach (var lessonProgress in progress.LessonProgress)
{
lessonProgress.Lesson // Works
lessonProgress.Lesson.Materials // NULL
}
The interesting thing here is that when I insert the row below inside the loop and on the first line the Materials list gets populated.
context.Lessons.Include(x => x.Material)
.SingleOrDefault(x => x.Id == lesson.Lesson.Id);
I also checked the tables and the data is OK. I suspect that something is wrong with the Include statement.
Thanks.
Try to use a string to specify the relationships
var progresses = context.UserProgresses
.Include("LessonProgresses.Lesson.Materials")
.SingleOrDefault(x => x.Id == progressId);
MSDN documentation
Or try this
var progresses = context.UserProgresses
.Include(u => u.LessonProgress.Select(l => l.Lesson).Select(m => m.Materials))
.SingleOrDefault(x => x.Id == progressId);
So the problem was that the LessonProgress was untracked and was added way back in the callstack. The Lesson was set using:
lessonProgress.Lesson = context.Lessons.SingleOrDefault(x => x.Id == lessonId);
Without including Materials. After doing a Include there, everything was all good.
I would like to get a collection of Customers including several properties among which is the address but only when it has not been deleted yet (SuppressionDate == null)
IQueryable<Customer> customers =
context.Persons.OfType<Customer>()
.Include(customer => customer.Addresses)
.Include(customer => customer.Bills)
.Include(customer => customer.Code)
.Include(customer => customer.Tutors);
I have tried several ways to use the where clause in order to filter address:
...
.Include(customer => customer.Addresses.Where(a => a.SuppressionDate == null))
.Include(customer => customer.Bills)
...
That was my first try but it raises the following exception:
System.ArgumentException : 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've also tried with the same where clause at the end of the Include() and at the end of the query but neither seems to work.
I'm currently using a workaround which is iterate through the collection of customer and remove the addresses that are deleted as such:
foreach(Customer c in customers){
customer.Addresses = customer.Addresses.Where(a => a.SuppressionDate == null).ToList();
}
Being fairly new to linq to object/entities, I was wondering if there was a built-in way to achieve this.
If you were getting a single customer you could use explicit loading like this:
var customer = context.Persons
.OfType<Customer>()
.Include(customer => customer.Bills)
.Include(customer => customer.Code)
.Include(customer => customer.Tutors)
.FirstOrDefault(); //or whatever
context.Entry(customer).Collections(x => x.Addresses).Query().Where(x => x.SuppressionDate == null).Load();
That makes a nice query and two simple calls to the database. But in this case you are getting a list (or collection or whatever) of customer and there's no shortcuts. Your "workaround" may cause a lot of chatter with the database.
So you probably just have to take it one step at time:
//1. query db to get customers
var customers = context.Persons
.OfType<Customer>()
.Include(customer => customer.Bills)
.Include(customer => customer.Code)
.Include(customer => customer.Tutors)
.ToList();
//2. make an array of all customerIds (no db interation here)
var customerIds = customers.Select(x => x.CustomerId).ToArray();
//3. query db to get addresses for customers above
var addresses = context.Addresses.Where(x => customerIds.Contains(x.CustomerId).ToList();
//4. assign addresses to customers (again, no db chatter)
foreach (var customer in customers)
{
customer.Addresses = addresses
.Where(x => x.CustomerId == customer.CustomerId && x.SuppressionDate == null)
.ToList();
}
Not too bad- still just two queries to database.
How can I get a list of unique items using LINQ preferably with GroupBy()?
This would be my try:
public IEnumerable<Owner> GetAll(int userId)
{
return _dbContext.Owners.Where(x => x.UserId == userId)
.GroupBy(p => p.Text).Select(x => new Owner()).ToList();
}
But this got me this run time error:
The entity or complex type 'CentraVent.Data.Owner' cannot be constructed in a LINQ to Entities query.
I have to say that this was one of my many tries. I can only find examples that return an anonymous type. How can this be done for a strongly typed object?
EDIT with a unique list of Owners, I meant it based on the Text column. So no record should have the same value for Text column. And it doesn't matter which of the duplicates I get.
The Owner table has the following fields:
Id
Text
Color
UserId
If it doesn't matter which Owner you want for each unique Text value then you can just get the first one
public IEnumerable<Owner> GetAll(int userId)
{
return _dbContext.Owners.Where(x => x.UserId == userId)
.GroupBy(p => p.Text).Select(x => x.FirstOrDefault()).ToList();
}
Maybe you mean this?
.GroupBy(p => p.Text).Select(x => new { owner = x }).ToList();
or
.GroupBy(p => p.Text).Select(x => new { owner = x.Owner }).ToList();
hard to tell without seeing the data model
I am getting a compile time error when compiling the below code and I can't see why:
Relations are many to many relations
var contacts = groups_to_querry
.SelectMany(x => x.Contacts)
.Where(x => x.ID == Guid.Empty)
.SelectMany(p => p.ContactDetails)
.Where(x => x.ID == Guid.Empty)
.SelectMany(x => x.Contacts); //This line gives me a compile time error
//Error : The Type argumetns for method 'System.Linq.Enumerable.SelectMany<TSource,Tresult>
//(System.Collections.Generic.IEnumerable<TSource>, System.Func<TSource,
//System.Collections.Generic.IEnumerable<TResult>>)' cannot be infrred from the usage.
//Try specifying the type arguments explicitly
The second time you call for .SelectMany(x => x.Contacts), you are currently working with a collection of ContactDetails. It is doubtful that you would be able to use SelectMany on it. You would need to use Select instead.
SelectMany is used when you want to select multiple collections of items and put them into one IEnumerable. Select is used on individual fields. Since you are working with objects of type ContactDetail (which I assume can only have one contact), you would need use Select
EDIT: Here is what you're doing in a nutshell, step by step:
groups_to_querry.SelectMany(x => x.Contacts): From all the groups that I want to query select all of their many contacts. Each group has many contacts, so put them all into a single IEnumerable collection of type Contact
.Where(x => x.ID == Guid.Empty): ...but only those Contacts with an empty ID
.SelectMany(p => p.ContactDetails): Then select all of those Contacts' many ContactDetails. Each Contact has many ContactDetails, so put them all into a single IEnumerable collection of type ContactDetail
.Where(x => x.ID == Guid.Empty): ...but only those ContactDetails with an empty ID
.SelectMany(x => x.Contacts);: Now select each of the ContactDetails' many Contacts. However, since the compiler knows that there is a one-to-many relationship between Contacts and ContactDetails (and not the other way around) that statement is not possible, and thus shows a compile error
I'm interpreting your intended query as "from multiple groups of contacts, select all contacts that have ID=Guid.Empty and also have details that all have ID=Guid.Empty".
The way your code is actually interpreted is "from all contacts that have Guid.Empty, select all details that have Guid.Empty, and from those details select all contacts". The first problem is that you end up selecting from details. This means the final SelectMany should be a Select, because x.Contacts here refers to the many-to-one relationship from details to contacts.
The second problem is that the result will contain duplicates of contacts, because the same contact is included for each details. What you should be doing instead is filtering the contacts directly based on their details collections, like this:
groups_to_query
.SelectMany(g => g.Contacts)
.Where(c => c.ID == Guid.Empty)
.Where(c => c.ContactDetails.All(d => d.ID == Guid.Empty))
Note this would also select contacts that have zero details, which is different behavior from your query, so I'm not sure if it's what you want. You could add another filter for ContactDetails.Any() if not.
Edit: Since you're using Entity Framework, the above probably won't work. You may need to select the details in a subquery and then filter in memory after it executes:
var queryResult =
groups_to_query
.SelectMany(g => g.Contacts)
.Where(c => c.ID == Guid.Empty)
.Select(c => new {
contact = c,
detailIDs = c.ContactDetails.Select(d => d.ID)
}).ToList();
var contacts =
queryResult
.Where(r => r.detailIDs.All(id => id == Guid.Empty))
.Select(r => r.contact);
I have a PostInfo table and LikeInfo Table,PostInfo have list of LikeInfo (for post likes).PostInfo table have a NotMapped property named of "LikeCount".
I want select list of PostInfoes and join to LikeInfo table and calcualte count of LikeInfoes of post and fill count of this to LikeCount property.
Here is my sample:
var query = context.PostInfoes.Where(x => x.UserId == userId).Include(x => x.LikeInfoes);
foreach (var item in query)
{
item.LikeCount = item.LikeInfoes.Count;
}
return query.ToList();
That is not good way for me because I do foreach on query and set LikeCount manualy however I dont want/need include full peoperties of LikeInfo table in this case.
I'm finding the best and easy way to fill this property.
Since EF6 does not allow projecting to entity type, you need to use LINQ to Entities query with intermediate anonymous type projection containing all necessary data, then switch to LINQ to Objects (via AsEnumerable()) and do the final projection, using a delegate block to perform the necessary unmapped property fixups:
var result = context.PostInfoes
.Where(x => x.UserId == userId)
.Select(x => new { Info = x, LikeCount = x.LikeInfoes.Count() })
.AsEnumerable()
.Select(x =>
{
x.Info.LikeCount = x.LikeCount;
return x.Info;
})
.ToList();