Say I have a
TableA
string Name
string Description
TableB
string Name
string Value
TableA and TableB are joined by Name. (In theory, i.e. not enforced in DB)
I want to create an object:
public MyObject
{
string Name
string Description
List<string> Values
}
I'm tying to understand how to combine these using LINQ.
var tableA = _oda.GetTableA();
var tableB = _oda.GetTableB();
var model = from a in tableA
join b in tableB on a.NAME equals b.NAME
select new MyObject
{
Name= a.Name,
Description = a.Description,
Values = "<Not sure to get list of tableb.Value>"
};
If it's an inner join, you can use GroupBy after your join:
var tableA = new List<TableA> { new TableA { Name = "1", Description = "D1" }, new TableA { Name = "2", Description = "D2"} };
var tableB = new List<TableB> { new TableB { Name = "1", Value = "V1" }, new TableB { Name = "1", Value = "V2"} };
var result = tableA.Join(tableB, a => a.Name, b => b.Name, (a, b) => new { A = a, B = b})
.GroupBy(k => k.A, e => e.B.Value)
.Select(g => new MyObject
{
Name = g.Key.Name,
Description = g.Key.Description,
Values = g.ToList()
});
foreach (var res in result)
{
Console.WriteLine("Name: {0}, Description: {1}, Value: {2}", res.Name, res.Description, string.Join(", ", res.Values));
}
Didn't try the code, but something like this should work.
var result = from a in TableA
join b in TableB on a.Name equal b.Name
group b.Value by a into g
select new MyObject
{
Name = g.Key.Name,
Description = g.Key.Description,
Values = g.ToList()
}
Related
I have a table like below: I need to display it as without duplicates. So I need to groupby customer alone. c1 has both 'Name'
Id Name customer
1 XXXX c1
2 YYYY c1
I need to get the values on c1 : xxx ,yyy. But its getting c1: xxx and c1: yyy.
My code is:
public List<data> GetComponentStatus()
{
List<data> d= null;
using(var entity=new FM())
{
d = entity.getdata()
.Select(
a => new data
{
Customer = a.id,
Name = a.name,
})
.GroupBy(a=>a.Customer).Select(a=>a.FirstOrDefault()).ToList();
}
return d;
}
From this, I am getting the first record or last record when using LastorDefault().
I want to get both 'Name' on single Customer C1.
If I understood correctly you want to group by Customer and get Name as comma seperated. I created sample data of yours and wrote LINQ in query syntax. See the demo output on rextester below.
var data = new[] { new {ID = 1,Name = "XXXX", customer= "C1"},
new {ID = 2,Name = "YYYY", customer= "C1"},
};
var query = from a in data
group a by a.customer into grp
select new {Cutomer= grp.Key ,Name = string.Join(",",grp.Select (g => g.Name)) };
foreach (var e in query)
{
Console.WriteLine("Customer: {0} ,Name: {1}", e.Cutomer,e.Name);
}
Its Demo on rextester
So your code should be like this
public List<data> GetComponentStatus()
{
using(var entity=new FM())
{
var d = from a in entity.getdata()
group a by a.customer into grp
select new data {Cutomer= grp.Key ,Name = string.Join(",",grp.Select (g => g.Name))};
return d.ToList();
}
}
I have a linq query which is working fine.How can i use group by in this query.I need to group by username and itemid and i should get sum(Amount)(All are in table called Carts)
FoodContext db = new FoodContext();
List<CartListing> fd = (from e in db.FoodItems
join o in db.Carts on e.itemid equals o.itemid
where e.itemid == o.itemid
select new CartListing
{
Itemname =e.itemname,
Amount =o.amount,
Price=(float)(e.price*o.amount),
}).ToList();
CartModel vm = new CartModel { CartListings = fd };
I can't see username anywhere in your code example, but to group by Itemname and sum Amount, you would something like:
var grouped = fd.GroupBy(
cl => cl.Itemname,
(key, group) => new CartListing
{
Itemname = key,
Amount = group.Sum(cl => cl.Amount),
Price = group.Sum(cl => cl.Price)
});
To also group by username, just generate a text key containing both values, for instance delimited by a character you know will be contained in neither.
Use:
var grouped = fd.GroupBy((a => new { a.itemid,a.name }) into grp
select new MyClass
{
MyProperty1=grp.key.itemid,
MyProperty2 =grp.Sum(x=>x.whatever)
}
Public MyClass
{
public string MyProperty1 {get;set;}
public int MyProperty2 {get;set;}
}
This way it won't be anonymous
var list = dc.Orders.
Join(dc.Order_Details,
o => o.OrderID, od => od.OrderID, <-- what if i have 2 more parameters let say an ID and a REC on both table. ex.: o=> o.OrderID && o.ItemName, od => od.OrderID && od.Itemname then (o, od) but its result is error? is there another way?
(o, od) => new
{
OrderID = o.OrderID,
OrderDate = o.OrderDate,
ShipName = o.ShipName,
Quantity = od.Quantity,
UnitPrice = od.UnitPrice,
ProductID = od.ProductID
}).Join(dc.Products,
a => a.ProductID, p => p.ProductID, <-- at this point too?
(a, p) => new
{
OrderID = a.OrderID,
OrderDate = a.OrderDate,
ShipName = a.ShipName,
Quantity = a.Quantity,
UnitPrice = a.UnitPrice,
ProductName = p.ProductName
});
is it possible to use this lambda expression linq query with multiple parameters by joining 3 tables?
--- UPDATE STILL ERROR -- :(
var header = DB.Delivery_HeaderRECs.Join(DB.Delivery_DetailsRECs, <-- Red Line on DB.Delivery_HeaderRECs.Join
q => new { q.drNO, q.RecNO },
qw => new { qw.DrNO, qw.RecNO },
(q, qw) => new
{
DR = q.drNO,
DATE = q.DocDate,
RECNO = q.RecNO,
CUSTID = q.CustomerID,
CUSTADDR = q.CustomerADDR,
RELEASE = q.ReleasedBy,
RECEIVE = q.ReceivedBy,
REMARKS = q.Remarks,
ITEM = qw.ItemCode,
DESC = qw.ItemDesc,
QTY = qw.Qty,
COST = qw.Unit,
PLATENO = qw.PlateNo,
TICKETNO = qw.TicketNo
}).Join(DB.Delivery_TruckScaleRECs,
w => new { w.DR, w.TICKETNO },
we => new { we.DrNo, we.TicketNO },
(w, we) => new
{
DR = w.DR,
DATE = w.DATE,
RECNO = w.RECNO,
CUSTID = w.CUSTID,
CUSTADDR = w.CUSTADDR,
RELEASE = w.RELEASE,
RECEIVE = w.RECEIVE,
REMARKS = w.REMARKS,
ITEM = w.ITEM,
DESC = w.DESC,
QTY = w.QTY,
COST = w.COST,
PLATENO = w.PLATENO,
TICKETNO = w.TICKETNO,
TRANSAC = we.TransactionType,
FWEIGHT = we.FirstWeight,
SWEIGHT = we.SecondWeight,
NWEIGHT = we.NetWeight
}).FirstOrDefault();
I made up changes base on the answer but an error said above the statement:
"The type arguments for method cannot be inferred from the usage. Try specifying the type arguments explicitly". i think it's talking about the parameters i've made..
You can use anonymous type for the Join like this:
var list = dc.Orders.Join(dc.Order_Details,
o => new { o.OrderID, o.ItemName},
od => new { od.OrderID, od.ItemName},
...);
The anonymous type will be compiled to use the autoimplemented Equals and GetHashCode so that the equality will be derived by the equality of all the corresponding properties. Just add more properties as you want in the the new {....}. Note that the order of properties provided in the 2 new {...} should be the same order of correspondence. The names should also be matched, you can explicitly specify the names to ensure this (this is needed in some cases) such as:
new {OrderID = o.OrderID, Name = o.ItemName}
However in your case the property names will be used as the same properties of the item.
UPDATE
This update is just a fix for your specific parameters, I said that the property names should be the same, if they are not you have to explicitly name them like this:
var list = dc.Orders.Join(dc.Order_Details,
q => new {DrNO = q.drNO, q.RecNO},
qw => new {DrNO = qw.DrNO, qw.RecNO},
...);
var sql = #"SELECT
a.id AS `Id`,
a.thing AS `Name`,
b.id AS `CategoryId`,
b.something AS `CategoryName`
FROM ..";
var products = connection.Query<Product, Category, Product>(sql,
(product, category) =>
{
product.Category = category;
return product;
},
splitOn: "CategoryId");
foreach(var p in products)
{
System.Diagnostics.Debug.WriteLine("{0} (#{1}) in {2} (#{3})", p.Name, p.Id, p.Category.Name, p.Category.Id);
}
Results in:
'First (#1) in (#0)'
'Second (#2) in (#0)'
CategoryId and CategoryName has values since the following
var products = connection.Query(sql).Select<dynamic, Product>(x => new Product
{
Id = x.Id,
Name = x.Name,
Category = new Category { Id = x.CategoryId, Name = x.CategoryName }
});
Results in:
'First (#1) in My Category (#10)'
'Second (#2) in My Category (#10)'
I'm connecting to a MySQL database if that has anything to do with it.
The simplest way is to call them all Id (case-insensitive, so just a.id and b.id are fine); then you can use:
public void TestMultiMapWithSplit()
{
var sql = #"select 1 as Id, 'abc' as Name, 2 as Id, 'def' as Name";
var product = connection.Query<Product, Category, Product>(sql,
(prod, cat) =>
{
prod.Category = cat;
return prod;
}).First();
// assertions
product.Id.IsEqualTo(1);
product.Name.IsEqualTo("abc");
product.Category.Id.IsEqualTo(2);
product.Category.Name.IsEqualTo("def");
}
If you can't do that, there is an optional splitOn (string) parameter that takes a comma-separated list of columns to treat at splits.
Given a classic DB structure of Orders has zero or more OrderLines and OrderLine has exactly one Product, how do I write a LINQ query to express this?
The output would be
OrderNumber - OrderLine - Product Name
Order-1 null null // (this order has no lines)
Order-2 1 Red widget
I tried this query but is not getting the orders with no lines
var model = (from po in Orders
from line in po.OrderLines
select new
{
OrderNumber = po.Id,
OrderLine = line.LineNumber,
ProductName = line.Product.ProductDescription,
}
)
Here is an article which appears to explain how to achieve exactly what you are trying to do.
public static void OuterJoinSimpleExample()
{
var customers = new List<Customer>() {
new Customer {Key = 1, Name = "Gottshall" },
new Customer {Key = 2, Name = "Valdes" },
new Customer {Key = 3, Name = "Gauwain" },
new Customer {Key = 4, Name = "Deane" },
new Customer {Key = 5, Name = "Zeeman" }
};
var orders = new List<Order>() {
new Order {Key = 1, OrderNumber = "Order 1" },
new Order {Key = 1, OrderNumber = "Order 2" },
new Order {Key = 4, OrderNumber = "Order 3" },
new Order {Key = 4, OrderNumber = "Order 4" },
new Order {Key = 5, OrderNumber = "Order 5" },
};
var q = from c in customers
join o in orders on c.Key equals o.Key into outer
from o in outer.DefaultIfEmpty()
select new {
Name = c.Name,
OrderNumber = ((o == null) ? "(no orders)" : o.OrderNumber)
};
foreach (var i in q) {
Console.WriteLine("Customer: {0} Order Number: {1}",
i.Name.PadRight(11, ' '), i.OrderNumber);
}
Console.ReadLine();
}
This is the working query (built using the example linked above):
var model = (from po in orders
join line in orderLines // note this is another var, it isn't po.Lines
on po.Id equals line.OrderId into g
from line in g.DefaultIfEmpty()
select new
{
OrderNumber = po.Id,
OrderLine = line == null ? 0 : line.LineNumber,
ProductName = line == null ? string.Empty : line.Product.ProductDescription,
}
)
var model =
from po in Orders
from line in po.OrderLines.DefaultIfEmpty()
select new
{
OrderNumber = po.Id,
OrderLine = line != null ?
(int?)line.LineNumber : null,
ProductName = line != null ?
line.Product.ProductDescription : null
} ;