Entity Framework - referencing ID twice - entity-framework

I am new to EF, I just have a simple question. I already know how to have one-to-many relationship. but my question is this. Say I have 2 tables: QuestionPool and AnswerPool.
QuestionPool has QuesID, Question columns
AnswerPool has AnsID, QuesID, Answer, NextQuesID
My problem is: QuesID and NextQuesID will be coming from the QuestionPool and both will have the QuesID for reference. How can I use QuesID twice as reference?
Thanks,
Gilbert

Something like this?
var results = (from q in QuestionPool
join a in AnswerPool on q.QuesID equals a.QuesID
select new {
QuesID = q.QuesID,
AnswerQuesID = a.QuesID,
a.AnsID,
a.NextQuesID
}).ToList();

Related

Laravel and Eloquent: Specifying columns in when retrieving related items

This is a followup post to: Laravel 4 and Eloquent: retrieving all records and all related records
The solution given works great:
$artists = Artist::with('instruments')->get();
return \View::make('artists')->withArtists($artists);
It also works with just:
$artists = Artist::get();
Now I'm trying to specify the exact columns to return for both tables. I've tried using select() in both the statement above and in my Class, like this:
ArtistController.php
$artists = Artist::select('firstname', 'lastname', 'instruments.name')->get();
or:
$artists = Artist::with(array('instruments' => function($query) {
$query->select('name');
}))->get();
(as suggested here and while this doesn't throw an error, it also doesn't limit the columns to only those specified)
or in Artist.php:
return $this->belongsToMany('App\Models\Instrument')->select(['name']);
How would I go about getting just the firstname and lastname column from the artists table and the name column from instruments table?
Not sure what I was thinking. I think working on this so long got me cross-eyed.
Anyhow, I looked into this a lot more and searched for answers and finally posted an issue on GitHub.
The bottom line is this is not possible as of Laravel v4.1.
https://github.com/laravel/laravel/issues/2679
This solved it:
Artists.php
public function instruments() {
return $this->hasMany('App\Models\Instrument', 'id');
}
Note that I changed this to a hasMany from a belongsToMany which makes more sense to me as a musicians (or Artist) would have many Instruments they play and an Instrument could belong to many Artists (which I also alluded to in my previous questions referenced above). I also had to specify 'id' column in my model which tells the ORM that instrument.id matches artist_instrument.id. That part confuses me a bit because I thought the order for hasMany was foreign_key, primary_key, but maybe I'm thinking about it backwards. If someone can explain that a bit more I'd appreciate it.
Anyhow, the second part of the solution...
In ArtistsController.php, I did this:
$artists = Artist::with(array(
'instruments' => function($q) {
$q->select('instruments.id', 'name');
})
)->get(array('id', 'firstname', 'lastname'));
That gives me exactly what I want which is a collection of Artists that contains only the firstname and lastname columns from the artists table and the name column for each of the instruments they play from the instruments.
$artists = Artist::with(array('instruments' => function ($query) {
$query->select('id', 'name');
}))->get('id', 'firstname', 'lastname');

entity framework 4.0 multiple joins

This is my real world example.
I have 4 tables:
Person
Plan
Coverage
CoveredMembers
Each person can have many plans, each of those plans can have many coverages. Each of those coverages can have many CoveredMembers.
I need a query that will apply a filter on Plan.PlanType == 1 and CoveredMembers.TermDate == null.
This query should bring back any person who has a medical type plan that is not terminated.
This SQL statement would do just that:
SELECT Person.*, Plans.*, Coverages.*, CoveredMembers.*
FROM Person P
INNER JOIN Plan PL ON P.PersonID = PL.PersonID
INNER JOIN Coverage C on PL.PlanID = C.PlanID
INNER JOIN CoveredMember CM on C.CoverageID = CM.CoverageID
WHERE CM.TermDate = NULL AND PL.PlanType = 1
I have figured out how to do this using anonymous types, but I sometimes need to update the data and save back to the database - and anonymous types are read only.
I was given a solution that did work using JOIN but it only brought back the persons (albeit filtered the way I needed). I can then loop through each person:
foreach (var person in persons) {
foreach (var plan in person.Plans{
//do stuff
}
}
But wouldn't that make a db call for each iteration of the loop? I have 500 persons with 3 unterminated medical plans each, so it would call the db 1500 times?
This is why I want to bring the whole data tree from Persons to CoveredMembers back in one shot. Is this not possible?
I believe this is accomplished in two parts:
Your query to determine the people you wish to have returned based on your criteria as discussed in this question previously: Entity framework. Need help filtering results
Properly setting the navigation properties for entities you want brought together to be eagerly loaded: http://msdn.microsoft.com/en-us/data/jj574232.aspx
For example if your Person entity looks like:
public class Person {
public List<Plan> Plans {get; set;}
...
}
When returning data from the dbcontext you can also use explicit eager loading with the include option:
var people = context.People
.Include(p => p.Plans)
.ToList();
....
If these are nested - coverage is part of plan, etc (which it looks like, it goes something like):
var people = context.People
.Include(p => p.Plans.Select(pl=>pl.Coverage).Select(c=>c.CoveredMembers)))
.ToList();
....
I am making some assumptions about your data model here, and my code above probably needs a little tweaking.
EDIT:
I might need someone else to weigh in here, but I don't think you can add the where clause into an include like that (my example above leads you that way a bit by putting the include on the context object, instead return an IQueryable with your conditions set as solved in your first post (without a ToList() called on it) and then use the code you wrote above without the Where clauses:
From first post (you supplied different criteria in this one, but same concept)
var q = from q1 in dbContext.Parent
join q2 in dbContext.Children
on q1.key equals q2.fkey
join q3 in ........
where q4.col1 == 3000
select q1;
Then:
List<Person> people = q.Include(p => p.Plans
.Select(pl => pl.Coverages)
.Select(c => c.CoveredMembers).ToList();
Again, doing this without being able to troubleshoot - I am sure it would take me a few attempts to iron this one out too.

one to many join - taking only the last one on the many part

I'm quite a newbie in EF, so I'm sorry if my question has been answered before.. I just can't figure out the syntax..
I have two entities, Category & Product, where one category has many products.
I want to get all categories, with only their latest product (it has a date property named timestamp)
I have no idea how to do that. :-/
If possible I'd like to know the syntax of the two ways to write it, both the sql-like syntax, and the C# like syntax, e.g.:
ctx.Categories.Include("Products").ToList()
from c in ctx.Categories.Include("Products")
Thanks!
Here's the SQL-like way:
var categories =
from p in products
group p by p.Category into g
select new { Category = g.TheKey, LatestProduct = g.Max(p => p.TimeStamp) };
This is the Lambda-way (warning, untested):
var categories = products.GroupBy(p => p.Category)
.Select(g => new { Category = g.TheKey,
LatestProduct = g.Max(p => p.TimeStamp)});
A note on Categories.Include("Products"), you don't need this in your example. You use "Include" for eager-loading, so that for example if you had a list of Categories returned from EF, when you do Categories.Product you will get the associated product.
But all you require is a list of categories, and a single product for each one - which is already returned in the above LINQ query, so no need for Include.

Entity Framework: Deleting multiple objects query

I have a List which hold the PK ID's of a number of objects in a collection that I want to remove. Does anyone know how to write a single query to retrieve these objects?
Eg:
IList<int> objectList; // populated with int Primary key Ids
using (MyEntities context = new MyEntities()){
var result = context.MyObjectCollection.Where(obj=> obj.ID IN objectList);
foreach(var item in result){
context.DeletObject(item);
}
context.SaveChanges();
}
Any help would greatly be appreciated!
var result = context.MyObjectCollection.Where(obj=> objectList.Contains(obj.ID));
Mel's answer doesn't work because in .NET 3.5 SP1 the EF doesn't know how to translate list.Contains(...) into T-SQL. Although this is coming in 4.0.
The workaround is to manually produce a big OR query i.e.
Where(obj => obj.ID == item1 || obj.ID == item2 ....)
Here is a tip I wrote that makes that easy:
Tip 8 - How to write where IN style queries using LINQ to Entities
Hope this helps
Alex James
Entity Framework Team - Read my Entity Framework Tips
http://efe.codeplex.com
this.Devices.Update(o => new Device() { LastOrderRequest = DateTime.Now, Description = "teste" }, o => o.Id == 1);

Accessing the relationship of a relationship with Entity Framework

I the School class I have this code:
from student in this.Students where student.Teacher.Id == id select student
The Student class there are two relationships: Teacher and School. In the School class I'm trying to find out all the students whose Teacher has a given id.
The problem is that I get
System.NullReferenceException: Object reference not set to an instance of an object.
in the statement
student.Teacher.Id
I thought of doing this.Students.Include("Teacher"), but this.Students doesn't have such a method. Any ideas how can I perform that query?
You show this line of code:
from student in this.Students where student.Teacher.Id = id select student
First, the = should be a ==
Is that just a typo?
Second, you don't need Include for the following, corrected query, if you don't dereference Teacher later on:
var q = from student in SomeObjectContext.Students
where student.Teacher.Id == id
select student;
LINQ to Entities doesn't require Inlcude for just the where clause.
You would need Include if you later iterated the results and dereferenced Teacher:
foreach (var student in q)
{
Console.WriteLn(student.Teacher.Id);
}
Third, you show this error:
System.NullReferenceException: Object reference not set to an instance of an object.
This is not a LINQ to Entities error. Is the error actually on that line of code, or is it somewhere else?
Also, what's this? If it's not an ObjectContext, then you are in likely LINQ to Objects, not LINQ to Entities. In that case, you wouldn't have Include available. If this is the case, then where does this.Sbudents come from?
I've found the debugger let me walk throu each iteration of the query:
from student in this.Students where student.Teacher.Id == id select student
so I've got to see student.Teacher.Id == id many times. Every time I was debugging it didn't happen and everything worked just fine. I turned the expression into:
from student in this.Students where student.Teacher != null && student.Teacher.Id == id select student
and it not only stopped crashing, but it worked fine as well (all students where selected as expected). I'm not totally sure why.
The Include clause can be used in linq to entities query. For example:
using (YourDataContext db = new YourDataContext())
{
var query = from s in db.Students.Include("Teacher")
where s.Teacher.ID == 1
select s;
//etc...
}
I guess that this.Students is collection pulled into memory already, so you might consider this code in the part you are retrieving students from dbs. If you want to load Teacher of the Student later on ( very important is that student entities are tracked by ObjectContext!) you can use the Load method on TeacherReference property, but for every student in this.Students collection separately:
student.TeacherReference.Load();
Hope this helps