In brief: is there any difference between fetching records using lambda expression vs using query expression?
In below example:
I fetched one employee record
Modified his salary Without saving
changes to context I fetch same record with Salary table included
Why are the results different when doing query 2 vs query 3?
var empdId = Guid.Parse("C8475622-09A9-4284-80D4-AAXXK");
//City for this employee was Washington in database
var emp = ctx.Employee
.FirstOrDefault(emp => emp.ID == empId);
emp.City = "New York"; //Modified the entity
//Lambda version
//Fetched again including foreign key relation Salary
var employeeCity = ctx.Employee.Include("Salary")
.FirstOrDefault(emp => emp.ID == empdId).City;
//New York
var cityfetchedAgain = from e in ctx.Employee
join sal in ctx.Salary on e.ID equals sal.EmployeeId
where e.ID == empdId
select e.City;
var city = cityfetchedAgain.FirstOrDefault();
//Washington
EDIT:
I will re-phrase my question: Include version of query returns the changed property, even if the changes are not committed to database. However LINQ Join is not aware of changes in the context (City property here). Records were fetched from database.
I have explicit foreign key configured between these tables. Should I
always prefer Include?
Related
I have a C# application where I am using Entity Framework to pull data from a database. This is the code I am executing:
var person = new List<Person>();
using (DevTestEntities db = new DevTestEntities())
{
person = (from p in db.People
join e in db.PersonEmails on p.Id equals e.Id
join t in db.PersonPhones on p.Id equals t.Id
where t.Phone == phoneNumber
select p).ToList();
}
var str = Newtonsoft.Json.JsonConvert.SerializeObject(person);
return str;
When the code runs, it fails on the select. I assume it is failing because there is a table within the database that is not part of the model. And because there is just a generic select, I assume Entity Framework is selecting all columns from all tables and doesn't know what to do with some of the columns.
What I really want to do is to be able to specify the columns that I want to return to the calling function. How do I specify what columns Entity Framework should select?
Thanks for any assistance.
EF will not fail because of tables in the DB that are not in model. It would help if you provided the error. Also, your query will result in selecting all columns from the People table but not the others.
An example answer to your question is this, it selects three columns from different tables and puts them in a new anonymous type:
var onlySomeColumns = (from p in db.People
join e in db.PersonEmails
on p.Id equals e.Id
join t in db.PersonPhones
on p.Id equals t.Id
where t.Phone == phoneNumber
select new {p.Id, e.email, t.phonenumber}).ToList();
I have a table Users which contain user information. I have a table Products which contain product information. I have a table called UserProduct which acts as a junction table and whose fields are UserId and ProductId. I am using a Entity Framework database first approach.
I want to outerjoin using Linq to find the following data.
All Users in the Users table.
All Users who have bought a particular product in terms of a Boolean called isPurchased.
My thinking was to left outer join table User with UserProduct and get all users and whether they have a product something like this.
var result = from a in Users
join b in UserProduct(Not available through EF) on a.Id equals b.prodId into group1
from g1 in group1.DefaultIfEmpty()
select new
{
id = g1.Id,
isPurchased = g1.prodId != null
}.ToList();
However in EF mapping, the object UserProduct is not created and so I cannot use it directly in my Linq query? So how do I go about this? Is there a way I can use linq to join tables with the actual table name(UserProduct) instead of joining entities?
Assuming Users contains a property List<Products> products to represent the junction information, and a variable boughtProductId to represent the particular product:
var result = from u in Users
let isPurchased = u.products.Any(p => p.Id == boughtProductId)
select new {
id = isPurchased ? boughtProductId : null,
isPurchased
}.ToList();
I am trying to figure out how to perform a conditional query on an Employees table to bring back all of their assigned Projects, but the caveat I don't quite understand on how to implement is that for every Employee, there is 0 to 1 EmployeeAssistant (self-joining entity). So when I select EmployeeID=2 and it has an EmployeeAssistantID=5, I would like to display all of the Projects for both of these individuals, i.e. the main Employee (EmployeeID=2) and their assistant (EmployeeID=5).
The tables look like:
Employees
- EmployeeID -- (Pkey)
- EmployeeAssistantID -- (Fkey to Employees.EmployeeID)
- other fields
-
Projects
- ProjectID -- (PKey)
- EmployeeID -- (Fkey to Employees.EmployeeID)
- other fields
I attempted the following in LINQ:
var projects = Projects.Include(proj => proj.Employee)
.Select(x => new
{
proj.ProjectID,
proj.ProjectName,
proj.Employee.Name
// ... not sure how to bring back another layer of projects for the EmployeeAssistant?
})
You can use the following Linq query to get the data you want:
var query = from e in Employees
join a in Employees on e.EmployeeAssistantID equals a.EmployeeID
where e.EmployeeID == 2
select new
{
EmployeeID = e.EmployeeID,
AssistantID = a.EmployeeID,
EmployeeProjects = Projects.Where(p => p.EmployeeID == e.EmployeeID),
AssistantProjects = Projects.Where(p => p.EmployeeID == a.EmployeeID)
};
The anonymous type returned by the query contains all of the data from both employee entities, as well as all of the Project data of each employee (some can be the same, others might differ).
I believe you mean to do the following:
var employeeIDs = new[] { myEmployee.EmployeeID, myEmployee.EmployeeAssistantID };
var projects = Projects.Where(p => employeeIds.Contains(p.EmployeeID));
This will grab all projects that both the employee and the assistant have done, given a previously grabbed Employee record (which I've called myEmployee).
How do I update two tables at the same time using Linq-to-SQL?
var z = from a in db.Products
join b in db.ProductSubcategories on
a.ProductSubcategoryID equals b.ProductSubcategoryID
join d in db.ProductCategories on
b.ProductCategoryID equals d.ProductCategoryID
select new { ProductName = a.Name, ProductCategory = d.Name,
ProductSubCategory = b.Name, Cost = a.StandardCost,
discontinuedDate = a.DiscontinuedDate,
ProductId=a.ProductID };
You have to update individual records from each table and then execute db.SubmitChanges();
In your query the output is an anonymous type, not a table type connected to the db context.
If you think in terms of SQL, linq2sql works pretty much the same. You can select a record set with a join, but you cannot update directly on this. You need to break it up and modify entries directly on Products, ProductCategories and ProductSubCategories, which equals the tables in your database.
If you want to modify a Product in Products then you have to modify the properties of that type, and not the anonymous type (joined type).
I'm using the Linq to Entities. I've got my main table, Employee setup with a field named vendorID. Vendor ID is a foreign key into the Vendors table.
As it is right now, the Employee object does not directly expose the vendorID. Instead, I can only access it this way:
var employee = (from e in context.Employees.Include("tbl_vendors")
where e.employeeID = 1
select e).FirstOrDefault();
//this gets the vendor ID
int vendorID = employee.tbl_vendors.vendorID;
That is just fine and dandy, but it is extra work on the database because it is forcing a join where none is needed. Is there a way to get that key value without being forced to do a join to the tbl_vendors table?
Actually this is very simple you basically do this:
var tblVendorID = (from e in context.Employees
select e.tbl_vendors.ID).FirstOrDefault();
Even though this looks like you are doing a join L2E will optimize out the join.
Which you can confirm with code like this:
var results = from e in ctx.Employees
select e.tbl_vendors.ID;
var query = results as ObjectQuery<int>;
string sql = query.ToTraceString();
Hope this helps
Alex (Microsoft).
You can access the foreign key via the entity reference.
Employee employee = context.Employees.Single(e => e.employeeID == 1);
Int32 vendorID = (Int32)employee.tbl_vendorsReference.EntityKey.
EntityKeyValues[0].Value;
See MSDN for reference on the EntityReference and EntityKey classes.
Not sure about your object names here but you can grab the key from the entity key property without going to the database something like this:
var employee = (from e in context.Employees
where e.employeeID = 1
select e).FirstOrDefault();
//this gets the vendor ID
int vendorID = (int)employee.tbl_vendorsReference.EntityKey.EntityKeyValues[0].Value;