i want to join different column where the output would be this using linq
| Name | Address | Cellphone | Email |
| John | NY | n/a | johndoe#y.c |
| John | NY | 123456781 | n/a |
And i want my output to be one liner combined
| Name | Address | Cellphone | Email |
| John | NY | 123456781 | johndoe#y.c |
I Tried it on SQL server and this is the Query that answers the needed output
select a.ID, a.Name , a.Address ,(
SELECT wc1.[Values]
FROM Contact as wc1 where wc1.infoID = a.ID and wc1.ContactTypeID = 56) as Email
,(
SELECT wc1.[Values]
FROM Contact as wc1 where wc1.infoID = a.ID and wc1.ContactTypeID = 59) as Cellphone
from Info as a where a.ID = 100
Also tried it on Linq but it produces different row with same ID
var an = (from a in db.Info
join b in db.Contact on a.ID equals b.InfoID
where b.ContactTypeID == 56
|| b.ContactTypeID == 59
select new
{
a.ID,
a.LastName,
a.FirstName,
a.MiddleName,
b.ContactTypeID,
b.Values
}).ToList();
List<InfoList> wlist = new List<InfoList>();
foreach (var row in an)
{
InfoList ci = new InfoList
{
ID = row.ID,
Name = row.FirstName + " " + row.MiddleName + " " + row.LastName,
ContactType = GetLookupDisplayValById(row.ContactTypeID),
ContactValue = row.Values
};
wlist.Add(ci);
}
return Json(wlist.ToList(), JsonRequestBehavior.AllowGet);
Can someone help me translate this to a Linq Statement
Your SQL does not use JOIN, so why are you trying to introduce it in LINQ?
var an = (from a in db.Info
select new
{
a.ID,
a.LastName,
a.FirstName,
a.MiddleName,
Email = db.Contact.FirstOrDefault(b => b.InfoID == a.ID && b.ContactTypeIF == 56).Values,
Cellphone = db.Contact.FirstOrDefault(b => b.InfoID == a.ID && b.ContactTypeIF == 59).Values,
}).FirstOrDefault(x => x.ID == 100);
You can use the Pivot table the mentioned link shows how to use it: http://www.codeproject.com/Tips/500811/Simple-Way-To-Use-Pivot-In-SQL-Query
Related
This is my database
Product
+----+----------+
| Id | Name |
+----+----------+
| 1 | Product1 |
| 2 | Product2 |
| 3 | Product3 |
+----+----------+
Category
+----+-----------+
| Id | Name |
+----+-----------+
| 1 | Category1 |
| 2 | Category2 |
| 3 | Category3 |
+----+-----------+
ProductCategory
+----+------------+------------+
| Id | ProductId | CategoryId |
+----+------------+------------+
| 1 | 1 | 1 |
| 2 | 1 | 1 |
| 3 | 2 | 2 |
+----+------------+------------+
Now, I want to get all products with its categories. In my repository I added this code:
public async Task<IEnumerable<Product>> GetAllProducts()
{
var products = await _dbConnection.QueryAsync<Product, Category, Product>(
#"
SELECT p.Id, p.Name, c.Id, c.Name
FROM Product p
LEFT JOIN ProductCategory pc on pc.ProductId = p.Id
LEFT JOIN Category c on c.Id = pc.CategoryId
",
(product, category) =>
{
product.Categories.Add(category);
return product;
}, splitOn: "Id",
transaction: _dbTransaction
);
return products.GroupBy(p => p.Id).Select(g =>
{
var product = g.First();
product.Categories = g.Select(p => p.Categories.Single()).ToList();
return product;
});
}
In results, I got list of 3 items:
Product1 with 2 categories (Category1, Category2)
Product2 with 1 category (Category2)
Product3 with 1 category (null)
The problem is that I don't want Product3 to have filled category list with null value. What I wanted is to have empty Category list in this case. What should I do to achieve that?
Why not just change the mapping function to?:
(product, category) =>
{
if (category!=null)
{
product.Categories.Add(category);
}
return product;
}
That will of course fail for the .Single() in GroupBy, but how would you group by missing category anyway?
It's easier to return the raw data from the query first and then do some processing. Then you have all logic in one place. For example:
var products = await _dbConnection
.QueryAsync<Product, Category, (Product Product, Category Category)>(
#"
SELECT p.Id, p.Name, c.Id, c.Name
FROM Product p
LEFT JOIN ProductCategory pc on pc.ProductId = p.Id
LEFT JOIN Category c on c.Id = pc.CategoryId
"
,(product, category) => (product, category)
, splitOn: "Id"
,transaction: _dbTransaction
);
return products.GroupBy(pc => pc.Product.Id)
.Select(g =>
{
var product = g.First().Product;
product.Categories = g.Select(pc => pc.Category)
.Where(c => c != null).ToList();
return product;
});
The null check skips the null category that's inevitably in the SQL result set because of the outer joins.
I have 3 tables:
Recipe
RecipeIngredient (fk RecipeId)
RecipeTag (fk RecipeId)
Recipe
+-----+------------+-------------+------+
| Id | Name | Ingredients | Tags |
+-----+------------+-------------+------+
| 99 | Mango Sago | | |
| 100 | Tuna Melt | | |
+-----+------------+-------------+------+
RecipeIngredient
+-----+----------+------------+---------------------------------------------+----------+
| Id | Quantity | UOM | Name | RecipeId |
+-----+----------+------------+---------------------------------------------+----------+
| 115 | 2 | Pieces | Whole Ripe Mangoes | 99 |
| 116 | 1 | Pieces | Jolly Coconut Milk, 400ml | 99 |
| 117 | 2 | Tablespoon | Sugar | 99 |
| 118 | 1 | Cup | Cooked Tapioca Pearls | 99 |
| 119 | NULL | NULL | Mango Cubes | 99 |
| 120 | 1 | Pieces | Doña Elena 100% Tuna Shredded 185g, drained | 100 |
| 121 | 2 | Tablespoon | White Onion, chopped | 100 |
| 122 | 2 | Tablespoon | Jolly Real Mayonnaise | 100 |
| 123 | 1 | Tablespoon | Celery or Pickle Relish, finely chopped | 100 |
| 124 | 8 | Pieces | White Bread | 100 |
| 125 | 4 | Pieces | Cheddar or Mozzarella Cheese | 100 |
+-----+----------+------------+---------------------------------------------+----------+
RecipeTag
+----+-----------------+----------+
| Id | Name | RecipeId |
+----+-----------------+----------+
| 72 | Filipino Desert | 99 |
| 73 | Quick Recipe | 99 |
| 74 | Quick Recipe | 100 |
+----+-----------------+----------+
How do I add all the RecipeIngredient to the Ingredients column in the Recipe table and add all the RecipeTag to the Tags column in the Recipe table in the controller?
public JsonResult GetAllRecipes()
{
var recipes = db.Recipes.OrderBy(a => a.Name).ToList();
return new JsonResult { Data = recipes, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
}
public JsonResult GetAllRecipes()
{
var recipes = (from rec db.Recipes
join ing in db.Ingredients on rec.Id equals ing.RecipeId into subIngrs
from subIngr in subIngrs.DefaultIfEmpty()
join tag in db.RecipeTags on rec.Id equals tag.RecipeId into subTags
from subTag in subTags.DefaultIfEmpty()
order by rec.Name
select new
{
rec.Id,
rec.Name,
Quantity = subIngr == null ? null : subIngr.Quantity,
IngrName = subIngr == null ? null : subIngr.Name,
UOM = subIngr == null ? null : subIngr.UOM,
TagName = subTag == null ? null : subTag.Name
}).ToList()
.GroupBy(x => new { x.Id, x.Name }).Select(x => new
{
x.Key.Id,
x.Key.Name,
Ingredients = string.Join("," x.Where(y => y.IngrName != null).Select(y => $"{y.Quantity} {y.UOM} {y.Name}").Distinct()),
Tags = string.Join("," x.Where(y => y.TagName != null).Select(y => y.TagName).Distinct())
}).ToList();
return new JsonResult { Data = recipes, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
}
You can use STUFF if you want to do it in sql.
SELECT a.Id,
Recipe = a.Name,
Ingredient = STUFF((
SELECT ','
+ CAST(b.Quantity AS NVARCHAR(10)) + ' '
+ b.UOM + ' '
+ b.Name
FROM dbo.RecipeIngredient b
WHERE a.Id = b.RecipeId
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, ''),
Tag = STUFF((
SELECT ',' + c.Name
FROM dbo.RecipeTag c
WHERE a.ID = c.RecipeId
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '')
FROM Recipe a
Here's a Demo.
To execute the stored procedure and return the results as a json in your controller method
var recipies = db.Database.SqlQuery<RecipeVM>("NameOfStoredProcedure");
return Json(recipes, JsonRequestBehavior = JsonRequestBehavior.AllowGet);
where RecipeVM is
public class RecipeVM
{
public int Id { get; set; }
public string Name { get; set; }
public string Ingredient { get; set; }
public string Tag { get; set; }
}
Assuming you have set up your navigation properties correctly (i.e. Recipe contains public virtual ICollection<RecipieIngredient> Ingredients { get; set; } etc) then to get the data in the concatenated format you want,
public JsonResult GetAllRecipes()
{
var recipes = db.Recipes
.OrderBy(r => r.Name)
.ToList() // this is necessary because we need Linq to Objects for the string formatting
.Select(r => new // can be anonymous objects because we are returning a JsonResult
{
Id = r.Id,
Name = r.Name,
Ingredients = r.Ingredients
.Select(i => string.Format("{0} {1} {2}", i.Quantity, i.UOM, i.Name).TrimStart())
.Aggregate((c, n) => c + ", " + n),
Tags = r.Tags
.Select(t => t.Name)
.Aggregate((c, n) => c + ", " + n)
});
return Json(recipes, JsonRequestBehavior = JsonRequestBehavior.AllowGet);
}
Side note, your RecipeIngredient table indicates nullable values for Quantity and UOM hence the TrimStart. I am assuming that if either Quantity or UOM is null, then the other is also null
Alternatively, (in LINQ to SQL) you can use
var recipes = (from r in db.Recipies
join i in db.RecipeIngredient on r.Id equals i.RecipeId into Ingedients
join t in db.RecipeTag on r.Id equals t.RecipeId into Tags
orderby r.Name
select new
{
Name = r.Name,
Ingedients = Ingedients,
Tags = Tags
}).ToList()
.Select(x => new
{
Name = x.Name,
Ingredients = x.Ingedients
.Select(y => string.Format("{0} {1} {2}", y.Quantity, y.UOM, y.Name).Trim())
.Aggregate((c, n) => c + ", " + n),
Tags = x.Tags
.Select(y => y.Name)
.Aggregate((c, n) => c + ", " + n)
});
return Json(recipes, JsonRequestBehavior = JsonRequestBehavior.AllowGet);
I'm not exactly sure what you're trying to accomplish, but if you're trying to programatically insert this data from user input, you could just iterate over the ingredients/tags and build a string to insert into the relevant tables.
If you're trying to do this from existing data, then I'm not sure EF is the tool to use. I would just write SQL scripts to handle that.
I have these queries which retrieve results from multiple tables and want the expected result given below, Here is my code:
var q1 = (from sh in SessionHistories
where (System.DateTime.Now >= sh.FromDate && System.DateTime.Now <= sh.ToDate) && sh.IsDeleted == false
select sh
).ToList();
var FromDate = (from q in q1 select q.FromDate.Value).FirstOrDefault();
var ToDate = (from q in q1 select q.ToDate.Value).FirstOrDefault();
var allDates = (from idx in Enumerable.Range(0, (System.DateTime.Now - FromDate).Days)
select FromDate.AddDays(idx)).OrderBy(x => x.Date).ToList();
var q2 = (from ci in View_checkinout
where ci.EmployeeId == 2183
group ci by new { ci.CheckTime.Date } into g
select new
{
AttendanceDate = g.Key.Date,
EmployeeId = g.Select(x => x.EmployeeId).FirstOrDefault(),
CheckInTime = g.Select(x => new { x.CheckTime, x.CheckType }).Where(x => x.CheckType == "I").FirstOrDefault(),
CheckOutTime = g.Select(x => new { x.CheckTime, x.CheckType }).Where(x => x.CheckType == "O").OrderByDescending(x => x.CheckTime).FirstOrDefault()
})
.ToList();
var q3 = (from ad in allDates
join q in q2 on ad.Date equals q.AttendanceDate into outer
from o1 in outer.DefaultIfEmpty()
select new
{
o1,
ad
}).ToList();
and here is the expected result:
| EmployeeName | Designation | Late Arrivals| Short Leave| Half Leave| Full Leave| Cur. Month Total| Prev. Total|
|---------------|--------------|--------------|------------|------------|------------|------------|
| Name | Teacher| 0 | 0 |
| Name | Admin | 20 | 0 |
| Name | Peon | 0 | 30 |
I need help with doing a Left join in a linq statement. My T-sql query works as expected but I can't seem to get the wanted results from the Linq. I also realize that there are ton of questions like mine, but I can't seem to apply any of the solutions to my case.
Products table
+---+------------+-----------+
| |transportID | Type(int)|
+---+------------+-----------+
| 1 | 5 | 1 |
| 2 | 5 | 3 |
| 3 | 6 | 3 |
+---+------------+-----------+
Stores
+---+------------+-------------+
| |Name |Type1(string)|
+---+------------+-------------+
| 1 | Ho | 1 |
| 2 | He | 2 |
| 3 | Be | 3 |
| 4 | Ke | 4 |
| 5 | Fe | 5 |
+---+------------+-------------+
My wanted result is
+---+------------+-------------+
| |Type |Count |
+---+------------+-------------+
| 1 | 1 | 1 |
| 2 | 2 | 0 |
| 3 | 3 | 1 |
| 4 | 4 | 0 |
| 5 | 5 | 0 |
+---+------------+-------------+
My tsql that works as intended
SELECT
Type1,
Count(Pro.transportId) as Count
FROM dbo.stores as sto
left Join dbo.products as pro on (sto.Type1 = pro.Type AND pro.transportId=5)
Where Type1 is not null
group by Type1
ORDER BY Type1 * 1 ASC
My Linq attempt returns this.
+---+------------+-------------+
| |Type |Count |
+---+------------+-------------+
| 1 | 1 | 1 |
| 3 | 3 | 1 |
+---+------------+-------------+
Linq Statement.
var res = (from sto in _context.Stores
join pro in _context.Products on sto.Type1 equals System.Data.Objects.SqlClient.SqlFunctions.StringConvert((double)pro.Type).Trim()
where pro.transportId == transportId
group pro by pro.Type1 into pt1
select new TypeTransportation()
{
Type = pt1.Key, // Needs to be int
Count = pt1.Count()
}).ToList();
I've tried doing some defaultifempty but can't seem to make it work.
Here is MSDN link "How to: Perform Left Outer Joins" with LINQ: https://msdn.microsoft.com/en-gb/library/bb397895.aspx
You code should be like this:
var res = (from sto in _context.Stores
join pro in _context.Products on sto.Type1 equals System.Data.Objects.SqlClient.SqlFunctions.StringConvert((double)pro.Type).Trim() into grpJoin
from product in grpJoin.DefaultIfEmpty()
where product.transportId == transportId
group product by product.Type1 into pt1
select new TypeTransportation()
{
Type = pt1.Key, // Needs to be int
Count = pt1.Count()
}).ToList();
Wow .. lastly i did it ..
var transportId = 5;
var res = from s in _context.Stores
let Type = _context.Stores.Take(1).Select(x => s.Type1).Cast<int>().FirstOrDefault()
group Type by Type into pt1
select new TypeTransportation
{
Type = pt1.Key, // Needs to be int
Count = _context.Products.Where(i => i.transportId == transportId && i.Type == pt1.Key).Count()
};
foreach (var item in res)
{
Console.WriteLine(item.Type + " " + item.Count);
}
Console.ReadKey();
I can't do it in query syntax, but using extension method syntax it will be
var products = new[]
{
new {transportId = 5, Type = 1},
new {transportId = 5, Type = 3},
new {transportId = 6, Type = 3},
new {transportId = 5, Type = 3},
new {transportId = 5, Type = 5},
};
var stores = new[]
{
new {Name = "Ho", Type1 = "1"},
new {Name = "He", Type1 = "2"},
new {Name = "Be", Type1 = "3"},
new {Name = "Ke", Type1 = "4"},
new {Name = "Fe", Type1 = "5"},
};
var transportId = 5;
var res = stores
.GroupJoin(
inner: products
.Where(product =>
product.transportId == transportId),
innerKeySelector: product => product.Type,
outerKeySelector: store => Int32.Parse(store.Type1),
resultSelector: (store, storeProducts) =>
new
{
StoreType = store.Type1,
StoreName = store.Name,
ProductsCount = storeProducts.Count()
})
.ToList();
foreach (var item in res)
{
Console.WriteLine(item);
}
Just replace Int32.Parse with appropriate sql function call for actual DbContext query code.
With query syntax this is probably the best I can propose:
var res =
from store in stores
join product in
(from prod in products where prod.transportId == transportId select prod)
on store.Type1 equals product.Type.ToString() into storeProducts
select new
{
StoreType = store.Type1,
StoreName = store.Name,
ProductsCount = storeProducts.Count()
};
Basically you need to follow the left join pattern described in join clause (C# Reference). The only tricky part is the pro.transportId=5 condition in
left Join dbo.products as pro on (sto.Type1 = pro.Type AND pro.transportId=5)
The important thing is to not include it as where clause after the join.
One possible way to handle it is like this:
var res = (from sto in _context.Stores
join pro in _context.Products
on new { sto.Type1, transportId } equals
new { Type1 = pro.Type.ToString(), pro.transportId }
into storeProducts
from pro in storeProducts.DefaultIfEmpty()
group sto by sto.Type1 into pt
select new
{
Type = pt.Key, // the string value, there is no way to convert it to int inside the SQL
Count = pt.Count()
}).AsEnumerable() // switch to LINQ to Objects context
.Select(pt => new TypeTransportation()
{
Type = Convert.ToInt32(pt.Type), // do the conversion here
Count = pt.Count()
}).ToList();
or just apply it as where clause before the join:
var res = (from sto in _context.Stores
join pro in _context.Products.Where(p => p.transportId == transportId)
on sto.Type1 equals pro.Type.ToString()
into storeProducts
// the rest ... (same as in the first query)
Another detail to mention is that in order to make LEFT JOIN effectively apply, you need to group by the left table (Stores in your case) field (like in the original SQL query), thus ending up with a string key. If you wish to get the int key, there is no way to do it inside the db query, so you need to use a temporary projection, context switch and the final projection as shown above.
UPDATE: The last thing that I didn't realize initially is that the original SQL Count(Pro.transportId) is excluding NULLs from the right side of the join. So the final correct equivalent LINQ query is:
var res = (from sto in _context.Stores
join pro in _context.MyProducts
on new { sto.Type1, transportId } equals
new { Type1 = pro.Type.ToString(), pro.transportId }
into storeProducts
from pro in storeProducts.DefaultIfEmpty()
group new { sto, pro } by sto.Type1 into pt
select new
{
Type = pt.Key,
Count = pt.Sum(e => e.pro != null ? 1 : 0)
})
.AsEnumerable()
.Select(pt => new TypeTransportation()
{
Type = Convert.ToInt32(pt.Type),
Count = pt.Count
}).ToList();
I have a property database and I am trying to get all properties added by an user. The main table is called 'Property' and there are other tables which are 'PropertyPhotos', 'City' etc. A sample database is as follows:
'Property' table
PropertyId| Area| State| UserId | ...
1 | 1 | 1 | AAA | ...
2 | 2 | 3 | BBB | ...
3 | 1 | 1 | AAA | ...
'PropertyPhotos'
PropertyPhotoId| PropertyId| FileName | MainPic
1 | 1 | x1.jpg | 1
2 | 1 | X2.jpg | 0
3 | 2 | x3.jpg | 1
4 | 3 | x4.jpg | 1
5 | 3 | x5.jpg | 0
6 | 3 | x6.jpg | 0
'AreaLookUp'
AreaLookUpId | AreaDescription
1 | London
2 | Birmingham
3 | Manchester
I am trying to write a LINQ query to get information on property added by a particular user. But I am stuck when trying to retrieve the 'FileName' of the MainPic and also get count. See code below with comments.
So, for the data above, this query should return the following for "UserId = AAA"
PropertyId | ... | MainPicSrc | PhotoCount
1 | ... | x1.jpg | 2
3 | ... | xr4jpg | 3
Please help!
public IEnumerable<PropertyExcerptViewModel> GetAddedPropertyVmByUserId(string userId)
{
var addedProperties = from p in db.Property where p.UserId == userId
join pp in db.PropertyPhotos on p.PropertyId equals pp.PropertyId
join a in db.AreaLookUp on p.Area equals a.AreaLookUpId
select new PropertyExcerptViewModel
{
PropertyId = p.PropertyId,
PropertyType = p.PropertyType,
TransactionType = p.TransactionType,
IsPropertyDisabled = p.IsPropertyDisabled,
IsPropertyVerified = p.IsPropertyVerified,
IsPropertyNotified = p.IsPropertyNotified,
MainPicSrc = pp.FileName, // How to put where condition to only get FileName of just the Main Pic
PhotoCount = pp.Count(), // How to get count of all pics with a particular proprtyId
Price = p.Price,
NoOfBedrooms = p.NoOfBedrooms,
Area = a.AreaLookUpDescription,
ShortDescription = (p.Description.Length > 300) ? p.Description.Substring(0,300) : p.Description
};
return addedProperties.ToList();
}
I think where statement might be easier if you care about clear match
var data=(from c in db.Property from v in db.PropertyPhotos from
n in db.AreaLookUpId
where c.PropertyId==v.PropertyId && c.Area==n.AreaLookUpId && c.UserId=="AAA"
// the rest is your select
PhotoCount = v.Where(j=>j. PropertyId==c.PropertyId).Count()
This also works - I ended up doing it this way
var addedProperties = from p in db.Property
join ppic in db.PropertyPhotos on p.PropertyId equals ppic.PropertyId into pp
join a in db.AreaLookUp on p.Area equals a.AreaLookUpId
join cal in db.CalendarEvent on p.PropertyId equals cal.PropertyId into c
where p.UserId == userId
select new PropertyExcerptViewModel
{
PropertyId = p.PropertyId,
PropertyType = p.PropertyType,
PropertyCategoryDescription = pc.PropertyCategoryDescription,
TransactionType = p.TransactionType,
IsPropertyDisabled = p.IsPropertyDisabled,
IsPropertyVerified = p.IsPropertyVerified,
IsPropertyNotified = p.IsPropertyNotified,
MainPicSrc = pp.Where(e => e.MainPic == true).FirstOrDefault().PhotoLocation,
PhotosCount = pp.Count(),
Price = p.Price,
NoOfBedrooms = p.NoOfBedrooms,
Area = a.AreaLookUpDescription,
ShortDescription = (p.Description.Length > 300) ? p.Description.Substring(0, 300) : p.Description,
LatestCalendarEvent = c.OrderByDescending(e => e.DateSaved).FirstOrDefault()
};
return addedProperties.ToList();