I am developing an application in asp.net MVC, and for show multi-table in the same view, I have created one big ViewModel which contains the three models (employee, user, and request)
now my problem is my query that not work, and I can't locate the problem
Thank you for your help
Sorry for my english is not good
My bigviewmodel
namespace freegest.Models
{
public class ControleViewModel
{
public List<employe> employes { get; set; }
public List<demande > demandes { get; set; }
public List<utilisateur> utilisateurs { get; set; }
}
}
My query
public ActionResult listdemande()
{
int id = Convert.ToInt32(Session["id_utilisateur"]);
ControleViewModel CV = new ControleViewModel();
CV = (from a in CV.utilisateurs
join b in CV.demandes
on a.id_utilisateur equals b.idutilisateur_demande
join c in CV.employes
on a.idemploye_utilisateur equals c.id_employe
orderby c.nom_employe ascending
where a.id_utilisateur == id
select new ControleViewModel
{
c.nom_employe ,
});
return View(CV);
}
Try the following approach to join multiple tables using LINQ:
public ActionResult Index()
{
using (DBEntities db=new DBEntities())
{
List<Employee> employees = db.Employees.ToList();
List<Department> departments = db.Departments.ToList();
List<Incentive> incentives = db.Incentives.ToList();
var employeeRecord = from e in employees
join d in departments on e.Department_Id equals d.DepartmentId into table1
from d in table1.ToList()
join i in incentives on e.Incentive_Id equals i.IncentiveId into table2
from i in table2.ToList()
select new ViewModel
{
employee=e,
department=d,
incentive=i
};
return View(employeeRecord);
}
}
Related
I have this entities:
Product
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
}
PriceList
public class PriceList
{
public int Id { get; set; }
public string Name { get;set; }
}
PriceListProduct
public class PriceListProduct
{
public int Id { get; set; }
public int PriceListId { get; set; }
public int ProductId { get; set; }
public virtual Product Product { get; set; }
}
Question is, how can I get the products not in Price List using LINQ?
My first thought was the use of Contains, but the list of products could be greater than 100000, if Contains is translate as a query like WHERE NOT IN clause, SQL has an approximate limit of 2000 parameters, so besides performance, I think this is not the best approach.
Is there another way? Should I use raw queries?
Update # 1
I'm trying to understand GroupJoin following #Indregaard answer. So far I have this.
var productsWithNoPrice = db.Product()
.GroupJoin(db.PriceListProduct().Where(plp => plp.PriceListId == 2)
.Select(plp => plp.Product),
p => p.Id,
plp => plp.Id,
(p, product) => new { p.Id, Product = product })
.Where(p => !p.Product.Any())
.Select(p => p.Product);
With the filter
.Where(plp => plp.PriceListId == 2)
I'm filtering products from Price List with Id 2. I think this is close but the query generated by SQL returns a number of rows that corresponding to the number of products that not exists in the Price List but every single column is null.
Basically what I need is a query like this
select * from Product p
left join PriceListProduct plp on plp.ProductId = p.Id and plp.PriceListId = 2
where plp.Id is null
So you are looking for Antijoin.
Manual approach could be like this:
var query =
from p in db.Products
join plp in db.PriceListProducts
on p.Id equals plp.ProductId into priceLists
where !priceLists.Any()
select p;
Another way:
var query = db.Products
.Where(p => !db.PriceListProducts.Any(plp => p.Id == plp.ProductId));
But the best way is to create all navigation properties in the model
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<PriceListProduct> PriceLists { get; set; }
}
and let EF create queries for you
var query = db.Products.Where(p => !p.PriceLists.Any());
Have you tried Join/GroupJoin?
I haven't tried against a database to see if the generated sql is valid/working but against regular objects something like this will work.
var productsWithNoPrices = products.GroupJoin(productPriceList,
product => product.Id,
productprice => productprice.ProductId,
(product, productPrice) => new { Product = product, Prices = productPrice})
.Where(c=>!c.Prices.Any()).Select(c=>c.Product);
Edit: Based on your updated question I think you want something like this:
var productsWithNoPrices = db.Products.GroupJoin(db.PriceListProducts.Where(c => c.PriceListId == 2),
product => product.Id,
productprice => productprice.ProductId,
(product, productPrice) => new { Product = product, Prices = productPrice }).Where(c=>!c.Prices.Any()).Select(c=>c.Product);
GroupJoin will take whats in your left table (db.Products), join with whats in your right table (db.PriceListProducts.xxxxx) (parameter 1): each product from the left table will get a list of matches from right, combined on product ids (param 2 and 3), output to a anonymous type (param 4). Filter all this on where there is no productprice and select the products. This results in the following SQL, which seems to give the desired result?
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Name] AS [Name]
FROM [dbo].[Products] AS [Extent1]
WHERE NOT EXISTS (SELECT
1 AS [C1]
FROM [dbo].[PriceListProducts] AS [Extent2]
WHERE (2 = [Extent2].[PriceListId]) AND ([Extent1].[Id] = [Extent2].[ProductId])
)
This is my controller:
public ActionResult product_list()
{
using(myDatabaseEntities1 d=new myDatabaseEntities1())
{
var a = (from g in d.departments
from p in d.Tables
where p.userid == g.kod_achrai
select new { department_name = g.department_name, oved_achrai = p.fullname, teur = g.teur });
return View(a);
}
}
The select statement base on 2 tables,
I want to show this in view.
I create a view but i dont know what to put in title
exp: #model MvcApplication4.department
I attach picture of option:
Can someone help me :)
Thank in advance.
I think you want to do scaffolding , so You have to create a model class for it. like
public class deptModel
{
public string department_name { get; set; }
public string oved_achrai { get; set; }
public string teur { get; set; }
}
and in your code write this
public ActionResult product_list()
{
using(myDatabaseEntities1 d=new myDatabaseEntities1())
{
var a = (from g in d.departments
from p in d.Tables
where p.userid == g.kod_achrai
select new deptModel { department_name = g.department_name, oved_achrai = p.fullname, teur = g.teur });
return View(a);
}
}
And thin in this model class list you will find deptModel ,to use/select.
and for using two tables yo can use join if you want like this.
var a = (from g in d.departments
join p in d.Tables
on p.userid equals g.kod_achrai
select new deptModel{ department_name = g.department_name, oved_achrai = p.fullname, teur = g.teur });
and whatever you meant by title exp will be #model MvcApplication4.deptModel
you can use scaffolding template like this in your solution
hope it will help you
I searched hours and hours for this without any luck. I'm trying to create a lambda expression to fetch data from two tables Schedule and Request. But i'm outputting a bool here. How can i do a proper left outer join to fix this?
this is the best i could come up with
ViewBag.RequestList = db.Requests
.Include(r => r.Department)
.Select(r => db.Schedules.Any(s => s.RequestId == r.RequestId));
but its a bool not a list.
Assume my table models are as follows
public class Request{
public virtual int RequestId { get; set; }
public virtual string Remarks { get; set; }
}
public class Schedule{
public virtual int ScheduleId{ get; set; }
public virtual string Name{ get; set; }
public virtual Request Request { get; set; }
}
I'm trying to see if each and every request has one or more schedules associated with it or not. so if i could attach schedule object to request and output it as a list then thats all i need.
But I want to do it using LINQ and lambda expressions and I've seen queries as below;
var leftList = (from emp in db.Requests
join d in db.Schedules
on emp.RequestId equals d.RequestId into output
from j in output.DefaultIfEmpty()
select new { RequestId = emp.RequestId,
name = emp.Department.Name,
route = emp.Route.Name });
But that's not what i want, because i have to specify every field i need in new { RequestId = emp.RequestId, name = emp.Department.Name, route = emp.Route.Name }
Thanks a lot!
just list what you want like this:
var leftList = from emp in db.Requests
join d in db.Schedules
on emp.RequestId equals d.RequestId into output
from j in output.DefaultIfEmpty()
select new
{
RequestId = emp.RequestId,
name = emp.Department.Name,
route = emp.Route.Name,
ScheduleId=j==null?0:j.ScheduleId,
SName=j==null?""j.Name,
};
Let's say I have two models:
public class User
{
[Key]
public int UserId { get; set; }
public string Name { get; set; }
}
and
public class Friend
{
[Key]
public int FriendId { get; set; }
public User A { get; set; }
public User B { get; set; }
}
Let's say I only have 2 users in my database (ids: 1 (Jon) and 2 (Sam)). Now I insert into table friend like this:
db.Friends.Add(new Friend()
{
A = db.Users.Find(1),
B = db.Users.Where(u => u.UserId == 2).First()
});
db.SaveChanges();
Suddenly, I find a user (3, Sam) in a table user. What is the reasoning behind this? Not completely sure if relevant or not, but note that even if I make A and B fields virtual, nothing changes.
UPDATE
Finally found how to reproduce my problem. Apparently the problem isn't exactly the same as I described.
User a, b;
using (var db = new DbConnection())
{
a = db.Users.First(u => u.UserId == 1);
b = db.Users.First(u => u.UserId == 2);
}
using (var db = new DbConnection())
{
db.Friends.Add(new Friend()
{
A = a,
B = b
});
db.SaveChanges();
}
Now users will have 4 users. Does it mean that if I step out of transaction, I can no longer access the entities as if they were exactly the same items in the current transaction? Or maybe there is a way to make the program know that I am referring to the same item (because the ID is the same)?
Honestly tried the same steps as you described and everything work well.. Anyway my steps
Created a db context class derived from `DbContext'
public class EFContext : DbContext
{
public DbSet<Friend> Friends { get; set; }
public DbSet<User> Users { get; set; }
public EFContext(string connectionString)
: base(connectionString)
{
}
}
I use MSQL2008 Express with win auth so I created the Users table
using (var db = new EFContext(#"Data Source=yourMachineName\SQLEXPRESS2008;Initial Catalog=DBName;Integrated Security=True;MultipleActiveResultSets=True"))
{
db.Users.Add(new User()
{
UserId = 1,
Name = "John"
});
db.Users.Add(new User()
{
UserId = 2,
Name = "Sam"
});
db.SaveChanges();
}
I checked my db and found 2 records
After I created the Friends table
using(var db = new EFContext(#"Data Source=yourMachineName\SQLEXPRESS2008;Initial Catalog=DBName;Integrated Security=True;MultipleActiveResultSets=True"))
{
db.Friends.Add(new Friend()
{
A = db.Users.Find(1),
B = db.Users.Where(u => u.UserId == 2).First()
});
db.SaveChanges();
}
Again I got 1 record in the Friends table with columns FriendId=1, A_UserId=1, B_UserId=2.
I checked the Users table and I still have 2 records.
If I were you I would try my code in a separate app. If it works then please post here all steps which led you to this problem.
Quite often our systems call stored procedures which output multiple tables worth of results. Previously we used XML outputs to get each table and relate them correctly using XSLT. If I were using ASP.NET MVC with LINQ calling a stored procedure, how do I get each of the tables and then output the data as necessary?
this article here explains everything. This is the same article which i linked, in your previous SO question.
There's an article here about LINQ to SQL and stored procedures, especially the section 'Handling Multiple Result Shapes from SPROCs':
LINQ to SQL - Retrieving Data Using Stored Procedures.
Is that useful in your case?
Otherwise, not using LINQ to SQL, maybe use SqlDataReader's NextResult to go through the results, for example:
IList<Employee> employees = new List<Employee>();
IList<Customer> customers = new List<Customer>();
using (SqlConnection connection = new SqlConnection
(Properties.Settings.Default.NorthwindConnectionString))
using (SqlCommand command = new SqlCommand
("GetEmployeesAndCustomers", connection))
{
command.CommandType = CommandType.StoredProcedure;
connection.Open();
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
Employee e = new Employee{EmployeeID = (int)reader["EmployeeID"]};
employees.Add(e);
}
reader.NextResult();
while (reader.Read())
{
Customer c = new Customer{CustomerID = (string)reader["CustomerID"]};
customers.Add(c);
}
}
}
Edit: Example of how to handle custom data combinations that are not easily fit into domain model objects; in this case retrieving orders along with the customers for the orders:
namespace Company.Application.ViewModel
{
public class CustomerOrder
{
public string CustomerID { get; set; }
public string CustomerName { get; set; }
public int OrderID { get; set; }
public DateTime? OrderDate { get; set; }
}
}
namespace Company.Application.Repository
{
public class CustomerOrderRepository
{
public IList<CustomerOrder> GetCustomerOrders()
{
NorthwindDataContext db = new NorthwindDataContext();
var custorders = from customer in db.Customers
join order in db.Orders
on customer.CustomerID equals order.CustomerID
select new CustomerOrder
{
CustomerID = customer.CustomerID,
CustomerName = customer.CompanyName,
OrderID = order.OrderID,
OrderDate = order.OrderDate
};
return custorders.ToList();
}
}
}
Inspiration for this: In the chapter about NerdDinner, Scott Guthrie talks about creating custom 'ViewModel' objects to hold data from for example joins that are not easily fit into the domain model objects.