Linq Join in c# - c#

friend i'm working in Linq. I use join in linq query with Entity Model as below.
var Records = from Cats in Context.Categories
join prod in Context.Products on Cats.Id equals prod.Category_Id
select new { CatName = Cats.Name, ProdName = prod.Name };
i want to convert the Record var in List of object, so i create a intermediate object which hold both entites values(product,category). Now when i cast this var to list like
List<test> testList = (List<test>)Records;
as Record.ToList(); is compiler error. how i cast the var object to list in order to bind it with listview in frontend. Is there any alternative in lambda which will be also appreciated. Is my approach is right?
my test class is as:
class test{
string catname;
string productname;
}

use ToList() on your query.
var Records = (from Cats in Context.Categories
join prod in Context.Products on Cats.Id equals prod.Category_Id
select new test { CatName = Cats.Name, ProdName = prod.Name }).ToList();
In order to make it work you need to define your test class as follows (you need to define properties)
public class test {
public string catname {get;set;}
public string productname {get;set;}
}

Create new Test and set the properties accordingly and finally call ToList
List<test> testList = (from c in Context.Categories
join p in Context.Products on c.Id equals p.Category_Id
select new Test{ Category= c, Product= p}).ToList();
If have class like below
public class Test{
public string CatName{ get; set; }
public string ProductnName{ get; set; }
}
List<test> testList = (from c in Context.Categories
join p in Context.Products on c.Id equals p.Category_Id
select new Test{ CatName= c.Name, ProductnName= p.Name}).ToList();

Related

Select count from joined tables

I have two tables, CaseProductLinks and Products as shown here:
I am trying to get the following information using LINQ:
Here's what I would do in SQL:
SELECT
p.ProductID, p.ProductName,
COUNT(c.CaseID) AS Frequency
FROM
CaseProductLinks c
JOIN
Products p ON c.ProductID = p.ProductID
GROUP BY
p.ProductID
Here's what I have in C# so far which throws a "System.InvalidOperationException":
var objs = from p in _db.CaseProductLinks
join c in _db.Cases on p.ProductId equals c.ProductId into g
select new S_Link
{
ProductID = p.ProductId,
ProductName = p.Product,
Frequency = g.Count() //Not sure what to do here
};
If you've set your navigation up correctly (i.e. a Product has an ICollection<CaseProductLink> CaseProductLinks) you can simply do:
var r = _db.Products.Select(p =>
new
{
p.ProductId,
p.ProductName,
Frequency = p.CaseProductLinks.Count()
}
);
Here's what I would do in SQL:
If you're quite used to SQL it can be a step to pull yourself away from thinking in those ways and into the ways that EF is designed to abstract over them. One of the big plus points of EF is in telling it how your database tables/entities relate to each other, and then it will form the joins. It's not some dumb device that has to be pummeled into making every join and group that it does; if it knew there was 1 Product with Many CaseProductLink then it can write the join/group that counts the number of relates CPL per P simply by accessing the collection on Product with an operation that aggregates (Count)
If you don't have this nav set up, then I really would recommend to do so, as it's a big chunk of the beauty of EF that makes C# side code nice to work with
I Test Below Code And Work Fine.Please check it
public class Productlinks
{
public int CaseId { get; set; }
public int ProductId { get; set; }
}
public class Products
{
public int ProductId { get; set; }
public string ProductName { get; set; }
}
static void Main(string[] args)
{
var products = new List<Products>()
{
new Products(){ ProductId=1, ProductName="A"},
new Products(){ ProductId=2, ProductName="B"},
new Products(){ ProductId=3, ProductName="C"},
};
var links = new List<Productlinks>()
{
new Productlinks(){ CaseId=1, ProductId=1 },
new Productlinks(){ CaseId=3, ProductId=2 },
new Productlinks(){ CaseId=3, ProductId=2 },
new Productlinks(){ CaseId=4, ProductId=3 },
};
var objs = from p in products
join c in links on p.ProductId equals c.ProductId into g
select new
{
ProductID = p.ProductId,
ProductName = p.ProductName,
Frequency = g.Count()
};
}

Cannot implicitly convert type 'System.Collections.Generic.List in asp mvc

i need join 4 tabel with Linq . but it show me this error :
Error 1 Cannot implicitly convert type 'System.Collections.Generic.List<>' to 'System.Collections.Generic.List' E:\MyProject\GoKhoda\GoKhoda\Areas\Classes\StudentsFunc.cs 20 20 GoKhoda
this is my code :
public List<Tbl_Students> ShowAllStudents()
{
var qstudent = from s in _db.Tbl_Students
join pr in _db.Tbl_Pye_Reshte on s.StudentID equals pr.StudentID
join r in _db.Tbl_Reshte on pr.ReshteID equals r.ReshteID
join p in _db.Tbl_Paye on pr.PayeID equals p.PayeID
orderby p.PayeID descending
select new { StudentName = s.StudentName, StudentFamily = s.StudentFamily, StudentImage = s.StudentImage, StudentPayeName = p.PayeName, StudentReshtName = r.ReshteName };
return qstudent.ToList();
}
Why Show Me Error ? How can i solve this ?
Use this:
var qstudent = from s in _db.Tbl_Students
join pr in _db.Tbl_Pye_Reshte on s.StudentID equals pr.StudentID
join r in _db.Tbl_Reshte on pr.ReshteID equals r.ReshteID
join p in _db.Tbl_Paye on pr.PayeID equals p.PayeID
orderby p.PayeID descending
select new Tbl_Students { StudentName = s.StudentName, StudentFamily = s.StudentFamily, StudentImage = s.StudentImage, StudentPayeName = p.PayeName, StudentReshtName = r.ReshteName };
return qstudent.ToList();
Select new { ... } will just create an anonymous type whch canĀ“t be converted to anything except object.
Just as an aside: you should consider naming your types depending on what an entity is within your application, in your example Student, not the table where the entity is stored.
The issue it that anonymous type is a return type from your LINQ query. This anonymous type is defined by compiler based on the names and types specified in the select new {} statement.
To fix it, you can define a new type Student
public class Student
{
public string StudentName { get; set; }
public string StudentFamily { get; set; }
public byte[] StudentImage { get; set; }
public string StudentPayeName { get; set; }
public string StudentReshtName { get; set; }
}
and then use Student type in LINQ's select statement and as return type for the ShowAllStudents method
public List<Student> ShowAllStudents()
{
var qstudent = from s in _db.Tbl_Students
join pr in _db.Tbl_Pye_Reshte on s.StudentID equals pr.StudentID
join r in _db.Tbl_Reshte on pr.ReshteID equals r.ReshteID
join p in _db.Tbl_Paye on pr.PayeID equals p.PayeID
orderby p.PayeID descending
select new Student { StudentName = s.StudentName, StudentFamily = s.StudentFamily, StudentImage = s.StudentImage, StudentPayeName = p.PayeName, StudentReshtName = r.ReshteName };
return qstudent.ToList();
}
Instead of an anonymous object use your model class in select. Then you can return List<StudentModel> instead of List<object>.

How to extract data from Linq query

I am new to Entity Framework, can anybody please tell how to extract data from following query and pass the result to the view.
public ActionResult Index()
{
var query = (from c in db.Customers
join b in db.Banks on c.Id equals b.CustomerId
join bt in db.BankTransactions on b.Id equals bt.BankId
where c.Id == 1
orderby bt.Id descending
select new
{
Name = c.Name,
Balance = bt.Balance
}).Take(1);
//I want to pass Customer Name and Customer Balance to the view
return View();
}
Create a view model
public class CustomerVM
{
public string Name { get; set; }
public decimal Balance { get; set; }
}
and modify your query to
var query = (from c in db.Customers ...
....
select new CustomerVM
{
Name = c.Name,
Balance = bt.Balance
}).FirstOrDefault();
then
return View(query);
View
#model YourAssembly.CustomerVM
...
#Html.DisplayFor(m => m.Name)
...
I didn't compile this snipet to check, but to solve your problem you could do something like this:
NewObject balanceInfo = query.AsEnumerable().Select(p => new NewObject
{
CostumerName = p.Name,
CostumerBalance = p.Balance
});
I do it a lot when my methods return lists. As I told, I didn't make a query and compiled to test, but I believe that this should solve your problem.

Using linq to store id in object, but display name in gridview?

If I've got a linq statement like this in my ASP.NET website:
var abcList =
(from c in backEnd.GetCList()
join a in backEnd.GetAList()
on c.AId equals d.AId
join b in backEnd.GetBList()
on c.BId equals e.BId
orderby c.CId descending
select new ABC
{
AId = a.AId,
BId = b.BId,
CId = c.CId,
}).ToList();
For the objects a and b, there is also a.AName and b.BName. I want to save the attribute ID in the object ABC, but I want the a.AName to be displayed instead of a.AId. Is that possible to solve?
So I want the object A to consist of the AId alone, but in a GridView I want to display the AName where c.AId = a.AId. Hope it's not too confusing.
Sure, just add a place for AName in ABC, and show it instead in your GridView.
public class ABC
{
public int AId { get; set; }
public string AName { get; set; }
// other stuff
}
// in your query
select new ABC
{
AId = a.AId,
AName = a.AName,
BId = b.BId,
CId = c.CId,
}
You could make this code a bit cleaner (IMO) if you move the property assignments to a constructor:
select new ABC(a, b, c)

Linq: select from multiple tables into one pre-defined entity

I have two tables A and B. The domain object pulls most of its data from A, and some aggregation from B.
For example:
Table A ( id, name );
Table B ( id_A, quantity );
class A {
public int id { set; get; }
public string name { set; get; }
}
class B {
public int id_A { set; get; }
public int quantity { set; get; }
}
var result =
from a in A join b in B on a.id equals b.id_A
group b by b.id_A into g
select new {
Name = a.name,
Total = g.Sum( b => b.quantity )
};
Instead of creating an anonymous type, I'd like to add a property to domain object A called it TotalQuantity and populate it with g.Sum( b => b.quantity ). I'd also like to turn result into IEnumerable instead of var.
My first bet was
class A {
public int id { set; get; }
public string name { set; get; }
public int TotalQuantity { set; get; }
}
IEnumerable<A> result =
from a in A join b in B on a.id equals b.id_A
group b by b.id_A into g
select new A {
name = a.name,
TotalQuantity = g.Sum( b => b.quantity )
};
This operation is not supported by the runtime:
System.NotSupportedException: Explicit construction of entity type 'Data.A' in query is not allowed.
Note that domain A and B doesn't contain any reference to each other. Their relationship is not used explicitly in the application, therefore, I chose not to model it.
How can I neatly populate a list of A without looping through the data stored in the instances of the anonymous class?
This should do it (note I have not tested it so some tweaking may be in order):
IEnumerable <A> result =
(from a in A join b in B on a.id equals b.id_A
group b by b.id_A into g
select new {
Name = a.name,
Total = g.Sum( b => b.quantity )
}).Select(obj => new A {Name = obj.Name, TotalQuantity = obj.Total});
You'll have perform your projection in memory instead of the database. This way the LINQ to SQL provider won't attempt to convert it to an SQL query.
Here's an example:
IEnumerable<A> result = (from a in A join b in B on a.id equals b.id_A
group b by b.id_A into g
select new
{
Name = a.name,
Total = g.Sum(b => b.quantity)
})
.ToArray()
.Select(item => new A
{
Name = item.Name,
TotalQuantity = item.Total
});
The call to the IQueryable<T>.ToArray() method will force the LINQ to SQL provider to run the query against the database and return the results in an array. The final projection is then performed in memory, circumventing the limitations of the LINQ to SQL provider.
Related resources:
LINQ and Deferred Execution
The performance implications of IEnumerable vs. IQueryable

Categories

Resources