Entity Framework Navigation property not working - c#

I have a many to many relationship like below.
Company[CompanyID, Name] - nav prop SalaryTabs
SalaryTab[ID,Salary, Since, CompanyId, Employeeid] - nav prop
(Company, Employee), and
Employee[EmployeeID,FirstName, LastName, DOB] -nav prop
(SalaryTabs)
But When I try to use Linq to query the tables using the navigation property. It wont just show up in the intellisence at all.
For example, I want to access contxt.SalaryTabs.Company.xxx The navigation property Company will not load the xxx and will not show up in the intellisence and if I manually type it. I get some errors.
If I try to do something like
//Delete an employee (identified via id) from a specific company(identified via id)
public bool DeleteEmployeeFromSpecificCompany(Guid employeeID, Guid companyID)
{
try
{
var emp = dbContext.Employees.FirstOrDefault(x => x.EmployeeID == employeeID);
dbContext.Companies.FirstOrDefault(x => x.CompanyID == companyID).SalaryTabs.Employee.Remove(emp);
dbContext.SaveChanges();
}
catch (Exception)
{
return false;
}
return true;
}
The navigation property doesn't work. I can't access context.Companies.SalaryTab.xxxx for example. I have been having this problem since yester which I didn't have before. I could navigate from one entity to another using the navigation properties but now it won't load and offer the options anymore.
I appreciate any input.

SalaryTabs - is collection. So, you need select one:
dbContext.Companies.FirstOrDefault(x => x.CompanyID == companyID).SalaryTabs.FirstOrDefault(...condition...)

I just can't navigate between entities anymore like before. I got the employee entity which i want to remove and the navigation wont let me through. I don't get the option to select the property I want to get to. I tried all day yesterday and it's the same until now.
var emp = dbContext.Employees.FirstOrDefault(x => x.EmployeeID == employeeID);
dbContext.Companies.FirstOrDefault(x => x.CompanyID == companyID).SalaryTabs.Employee.Remove(emp);
dbContext.SaveChanges();

Related

Entity Framework explicitly included navigation property is null

I've got lazy loading off, and proxy creation doesn't matter (tried both true and false, no difference).
I have this model:
public class Comment{
[Required]
public int SenderID { get; set; }
public User Sender { get; set; }
}
(and of course, I have a user class).
At database level, I confirm that the Sender is a valid User object. I have some IQueryable<Comment> named commentsQuery (that basically takes some comments from a post. Then I include the Sender navigation property and execute the query:
var comments = commentsQuery.Take(50).OrderBy(c => c.ID).Include(c => c.Sender).ToList();
However, some comment objects inside the list have their Sender set to null even though I've explicitly included the navigation property.
If I turn on lazy loading it works correctly, but I don't want to turn on lazy loading.
Why is the explicitly-included required navigation property null? (I'm on Entity Framework 6.1.3)
Okay, just figured out myself. I had to include the sender at the original query when I'm constructing it from the database context.
I was using:
var post = await Database.Posts.Where(p => p.ID == postId && p.Sender.Username == username).Include(p => p.Sender).Include(p => p.Comments).FirstOrDefaultAsync();
IQueryable<Comment> commentsQuery = post.Comments.ActiveObjects().OrderByDescending(c => c.ID).AsQueryable();
And then, I assume Entity Framework was just ignoring (I think it's a design issue at Microsoft's side) the later-included navigation property (commentsQuery.[...].Include(c => c.Sender)).
I've modified the original query to include the second-level navigation property:
var post = await Database.Posts.Where(p => p.ID == postId && p.Sender.Username == username).Include(p => p.Sender).Include(p => p.Comments).Include(p => p.Comments.Select(c => c.Sender)).FirstOrDefaultAsync();
(notice the addition of .Include(p => p.Comments.Select(c => c.Sender))
Now, my query works properly. I'm not sure if it's the best way to do it though, anyway, it's not the scope of this question.

LINQ Query is removing multiple rows instead of a single row

I have tried the following:
var itemtoremove = db.ItemGroups.Single(x => x.ID == _id);
if (itemtoremove != null)
{
db.ItemGroups.Remove(itemtoremove);
db.SaveChanges();
}
The query 'works' but it deletes more than one row! Any ideas? The table itself is part of a set or really terrible tables, but I've got to use them.
Can having multiple keys on a table affect what EF does?
Thanks folks.
If the enitity has a navigation property and you have not set CascadeOnDelete(false); you could potentially remove more than one item.
//check item group for duplicates (just as a test)
var items = db.ItemGroups.Where(x => x.ID == _id); //breakpoint here to make sure there is only one match. If there is only one then you are deleting a linked item to the entity you are deleting.
var itemtoremove = db.ItemGroups.Single(x => x.ID == _id);
if (itemtoremove != null)
{
db.ItemGroups.Remove(itemtoremove);
db.SaveChanges();
}
I found a resolution.
I think with the table having 2 PK's setup on it (both on CHAR fields) was causing EF to become confused. The table goes back years and it is part of a group of tables that do not relate to one another properly. It's pretty poor but that's another story!
So, I started from scratch again:
After re-importing the table in it's original format I did the following:
Removed the PK on 'GroupID' (should never have been a PK)
Added an ID column, set it as 'IsIdentity' so it will auto-generate an ID
refreshed my EF Model to include:
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
Now only the one correct row is removed when the SaveChanges is applied.
Thanks for your suggestions folks!

C# class code with data from multiple tables

Hello and thanks taking your time to help me.
When a user login hes User id is stored in a session, and when he enters my Survey page. I want to the page to display the Surveys that is avalible to him.
My Database Diagram:
I tried to Write the code so First it checks if there is any relations between the user and the surveys in the RelationShip table. I have made sure that part works with debugging because it returns 1 since there is 1 user and one survey + the relation with the correct information.
But it cant write the last part like this: lstItem = db.Survey.Where(x => x.ID == relation).ToList(); so it returns the Correct Survey to my repeater. Since there might be more Surveys avaliple to a user.
My class Code:
public class Surveys
{
public static List<Survey> getAll(int id)
{
List<Survey> lstItem = new List<Survey>();
using (KONE_Entities db = new KONE_Entities())
{
List<User_Survey_Relation> relation = new List<User_Survey_Relation>();
relation = db.User_Survey_Relation.Where(i => i.UserID == id).ToList();
if (relation != null)
{
lstItem = db.Survey.Where(x => x.ID == relation).ToList();
}
}
return lstItem;
}
}
My C# code that binds it to the repeater:
private void BindSurvey()
{
int id = Convert.ToInt32(Session["UserID"].ToString());
rpSurveys.DataSource = Surveys.getAll(id);
rpSurveys.DataBind();
}
So to Clarify what Im asking for/ need help with: My Code will not return the Survey or Surveys that has a relation with the user that is logged on to the site.
Thanks for your time and I hope you can help me.
Compare individual relation values and then add the result to lstItem .
foreach(User_Survey_Relation relatSingle in relation){
lstItem.addRange(db.Survey.Where(x => x.ID == relatSingle.SurveyID).ToList());
}
}
Sorry...dude ...compared the whole class,i have edited it...please check if surveyId has to be compared or Id
You can see from the comments what is wrong with your logic. In terms of how best to solve it, I believe your best option is to join your tables in a single query rather than running 2 queries. The SQL syntax would be:
select s.*
from Survey s
inner join User_Survey_Relation usr on s.ID = usr.SurveyID
where usr.UserID = id
Translating this to LINQ becomes (this is rough - I don't have VS to test):
lstItem = (from db.Survey in survey
join db.User_Survey_Relation in relation on survey.ID
equals relation.SurveyID
where relation.UserID = id
select survey).ToList();
Like I say, you may need to play around with this to iron out any wrinkles. Hopefully you get the idea though.

Creating a join using a link table and the Entity Framework

Right now I am struggling with ASP.Net and MVC3 to display a person.
I have a table with the person information, a table for type of person.
A person can be multiple types.
So I created a link table that links the personid and typeid.
I am struggling to find a way to p[ush both the user details and the different types they are part of.
So the ActionResult is taking a PersonID and I can display the person information just fine, but I also need to pass a list of the types they are part of.
Any help, examples or links to a tutorial would be great. Thanks in advance.
Here is what I have right now in my controller.
public ViewResult Details(long id)
{
champion champion = _db.champions.Single(c => c.id == id);
return View(champion);
}
I tried using a ViewBag object and a join statement but it got too complex and went beyond my knowledge of linq statements.
http://msdn.microsoft.com/en-us/library/bb738708.aspx
var champion = _db.champions.Include("TheOtherModel").SingleOrDefault(c => c.id == id);
return View(champion);
and you should've access to "TheOtherModel" by using
champion.TheOtherModel
or in your view:
#foreach (var item in Model.TheOtherModel){
item.Property1
....
}
(should contain a list).

With entity framework's self tracking entities, can I perform an explicit load?

I wish to return a graph for a "Business" entity. The Buiness entity has a collection of "Contacts".
So I basically want this:
ctx.Business.Include("Contacts").Where(b => b.BusinessID == id).Single();
The problem is I don't want ALL the contacts for the business. Just those that have a ContactTypeID = x. How can I accomplish this? I figured I may need to break the query into 2 steps. 1 to get the business and a 2nd to grab the contacts and then attach them to the business somehow.
But I'm using using the STE t4 template and I can't figure out how to do it using that.
I'd greatly appreciate any help.
One way for doing so is:
var biz = from b in ctx.Business where b.BusinessID == id
select new
{
Business = b,
Contacts = b.Contacts.Where(c => c.ContactTypeID == x)
}.ToList();
I think I found how to do it:
var biz = ctx.Business.Where(b => b.BusinessID == id).Single();
var contacts = ctx.Contacts.Where(c => c.BusinessID==id && c.ContactTypeID==6);
foreach (var contact in contacts)
{
biz.Contacts.Add(contact);
}
I was worried by adding the contacts this way they would be treated as "new" items but change tracking is off so they are treated as unchanged. I think change tracking only turns on once they are deserialized.

Categories