Calling a custom method in LINQ query - linq

I have a query like this:
var q =
from u in db.User
select new
{
userId = u.UserId,
userName = o.Name,
userAvatar = o.AvatarCode
};
Then, I have to transform AvatarCode to AvatarPath using custom static method Image.GetPath.
It's possible to make this in the following way:
var q =
(from u in db.User
select new
{
userId = u.UserId,
userName = o.Name,
userAvatar = o.AvatarCode
})
.AsEnumerable()
.Select(new
{
userId = u.UserId,
userName = o.Name,
userAvatar = Image.GetPath(o.AvatarCode)
};
But if the number of object fields is large then it's an overkill to duplicate all fields in the second Select.
Are there any alternatives?
For example, some approach to mark methods that should be executed after query execution:
var q =
from u in db.User
select new
{
userId = u.UserId,
userName = o.Name,
userAvatar = Linq.ExecuteLater(Image.GetPath(o.AvatarCode))
};

There is not any such method but if the problem is only number of fields which must be specified again in the second select you can do something like this:
var q =
(from u in db.User
select new
{
userId = u.UserId,
userName = u.Name,
userAvatar = u.AvatarCode
})
.AsEnumerable()
.Select(u => new
{
User = u,
Path = Image.GetPath(u.AvatarCode)
});

Related

Filtering data from 2 table

Here I have 2 query variable for showing a different type of data,But i want to extract a particular data from first query ,which don't have reference in second query
I have the following code,but it does not work properly as.first query variable is used to join 4 table like A,B,C,D and Second Query variable Join table A and B.Here i want a data from First variable and it don't have any reference in second table
public List<ProductEntityList> GetProductListRegister()
{
var ProductList1 = new List<ProductEntityList>();
var ProductList = new List<ProductEntityList>();
var finalList = new List<ProductEntityList>();
try
{
using (HabitGreen01Entities ob = new HabitGreen01Entities())
{
var list1 = from ctr in ob.TblCreateUsers
join shp in ob.TblShopMasters
on ctr.id equals shp.Fk_CreateUser_Id
join prd in ob.TblProductMaster01
on shp.id equals prd.FK_ShopMaster_Id
select new ProductEntityList
{
Id = prd.id,
Name = prd.Name,
ShopName = shp.Name,
UserName = ctr.Name
};
ProductList1 = list1.ToList();
var temp = from pd in ob.TblProductMaster01
join cr in ob.TblAccountSettings
on pd.id equals cr.f_productmaster01Id
select new ProductEntityList
{
Id = (int)cr.f_productmaster01Id,
Name=pd.Name
};
ProductList = temp.ToList();
var temp1 = from item in ProductList1
where !ProductList.Contains(x=>item.Id)
select new ProductEntityList
{
Id = item.Id,
Name = item.Name,
ShopName = item.ShopName,
UserName = item.UserName
};
finalList = temp1.ToList();
// var temp1= ProductList1.Select(f=>f.Id).Intersect(ProductList.Select(b=>b.Id));
//finalList = matches.ToList();
}
}
catch (Exception e)
{
throw e;
}
return (finalList);
}
Try this:
var temp1 = from item in ProductList1
where !ProductList.Select(c=>c.Id).Contains(item.Id)
select new ProductEntityList
{
Id = item.Id,
Name = item.Name,
ShopName = item.ShopName,
UserName = item.UserName
};
You can write directly:
var finalList = (from item in ProductList1
where !ProductList.Select(c=>c.Id).Contains(item.Id)
select new ProductEntityList
{
Id = item.Id,
Name = item.Name,
ShopName = item.ShopName,
UserName = item.UserName
}).ToList();
var result = ProductList1.Where(p => !ProductList.Any(p2 => p2.Id== p.Id));
finalList = result.ToList();

how to pass string variable to linq select new {} section

Ii just want to make search functionality with linq with multiple ColumnNames that stored to session variable. I'm using one method:
public void FillGrid(string CommandName,string ColumnName, string SearchText)
That has three string variable that stores session value.
Now I just want to pass ColumnName with this query:
var query1 = (from p in db.Posts
join c in db.Categories on p.Category_id equals c.Id
join u in db.Users on p.User_id equals u.Id
where (p.ToUser_id == user_id || p.ToUser_id == null) && p.User_id != user_id
orderby p.Sent_Datetime descending
select new
{
Id = p.Id,
Title = p.Title,
Publisher = u.First_name + " " + u.Last_name,
ToUser = p.ToUser_id,
PublishDate = p.Sent_Datetime,
IsFile = p.IsFileAttached,
CategoryName = c.Category_name,
status_name = (from s in db.Status where (s.Id == p.status_id) select s.status_name).FirstOrDefault(),
Group_name = (from g in db.Groups where (g.Id == p.group_id) select g.Group_name).FirstOrDefault(),
FileSize = p.TotalFileSize,
ColumnName = Sesssion["ColumnName"].ToString()
}).Where(q => q.ColumnName.Contains(SearchText));
However, ColumnName does not give any text or it may be not part of this query i have to manually give column name because.
for multiple column i have, so i can not use this statement like:
.Where(q => q.Tile.Contains(SearchText));
this query works fine with single column. but there is multiple column i have so i have to set q.ColumnName from outer side.
I would do an extension method for that kind of things, building an expression for your predicate.
public static class Helper
{
public static IQueryable<T> FilterForColumn<T>(this IQueryable<T> queryable, string colName, string searchText)
{
if (colName != null && searchText != null)
{
var parameter = Expression.Parameter(typeof(T), "m");
var propertyExpression = Expression.Property(parameter, colName);
var searchExpression = Expression.Constant(searchText);
var containsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) });
var body = Expression.Call(propertyExpression, containsMethod, searchExpression);
var predicate = Expression.Lambda<Func<T, bool>>(body, new[] { parameter });
return queryable.Where(predicate);
}
else
{
return queryable;
}
}
}
usage in your case
var query1 = (from p in db.Posts
join c in db.Categories on p.Category_id equals c.Id
join u in db.Users on p.User_id equals u.Id
where (p.ToUser_id == user_id || p.ToUser_id == null) && p.User_id != user_id
orderby p.Sent_Datetime descending
select new
{
Id = p.Id,
Title = p.Title,
Publisher = u.First_name + " " + u.Last_name,
ToUser = p.ToUser_id,
PublishDate = p.Sent_Datetime,
IsFile = p.IsFileAttached,
CategoryName = c.Category_name,
status_name = (from s in db.Status where (s.Id == p.status_id) select s.status_name).FirstOrDefault(),
Group_name = (from g in db.Groups where (g.Id == p.group_id) select g.Group_name).FirstOrDefault(),
FileSize = p.TotalFileSize,
}).FilterForColumn(Sesssion["ColumnName"].ToString(), SearchText);

Conversion of a LINQ query fom method syntax to query syntax

Hi I am changing career to computer programming. I am still in college. I have to change the following LINQ query from method syntax to query syntax. What gets me is the 2 steps process of the method query. First it gets a teamId and then it returns a list based on the context and using the teamId. I am confused about how to translate this to query method. Most of the questions are about going from query syntax to method.
Can someone Help?
public IEnumerable<TemplateView> GetTemplates(Guid userId, int languageId)
{
using (DigigateEntities context = new Models.DigigateEntities())
{
var teamId = context
.TeamMembers
.Include("Team")
.FirstOrDefault(c => c.UserId == userId)
.Team.Id;
return context
.TeamTemplates.Include("Template")
.Where(c => c.TeamId == teamId)
.Select(c => c.Template)
.Where(c => c.StatusId == 1/*Active*/)
.Select(k => new TemplateView
{
TemplateName = k.Name,
Id = k.Id,
IsCustom = k.Custom,
TypeId = k.TypeId,
TypeName = k.TemplateType.Description,
FileName = k.FileName,
TemplateImage = "test.png",
LanguageId = k.LanguageId,
LanguageName = k.Language.Name,
CreateDate = k.CreateDate
}).ToList();
}
}
The first one is pretty straight forward. I delayed the execution of the query until the end. Since you may get a null reference exception in your example accessing .FirstOrDefault().Team.Id;
var teamId = (from c in context.TeamMembers.Include("Team")
where c.UserId == userId
select c.Team.Id).FirstOrDefault();
This one you just need to use an into in order to continue your query statement
return (from c in context.TeamTemplates.Include("Template")
where c.TeamId == teamId
select c.Template into k
where k.StatusId == 1
select new TemplateView
{
TemplateName = k.Name,
Id = k.Id,
IsCustom = k.Custom,
TypeId = k.TypeId,
TypeName = k.TemplateType.Description,
FileName = k.FileName,
TemplateImage = "test.png",
LanguageId = k.LanguageId,
LanguageName = k.Language.Name,
CreateDate = k.CreateDate
}).ToList();
public IEnumerable<TemplateView> GetTemplates(Guid userId, int languageId)
{
using (DigigateEntities context = new Models.DigigateEntities())
{
var teamId = (from tm in context.TeamMembers.Include("Team")
where tm.UserId==userId
select tm.Id).FirstOrDefault();
IEnumerable<TemplateView> result = from k in (from tmp in context.TeamTemplates.Include("Template")
select tmp.Template)
where k.StatusId==1
select new
{
TemplateName = k.Name,
Id = k.Id,
IsCustom = k.Custom,
TypeId = k.TypeId,
TypeName = k.TemplateType.Description,
FileName = k.FileName,
TemplateImage = "test.png",
LanguageId = k.LanguageId,
LanguageName = k.Language.Name,
CreateDate = k.CreateDate
};
return result;
}

Merging two querys

What is the best way to go about joining two querys in linq? At the moment my code does not join them together.
var userprofilemodel1 =
(from u in db.UserProfiles
where u.UserId == 1
orderby u.FirstName, u.LastName
select new UserListViewModel
{
UserId = u.UserId,
UserName = u.UserName,
FirstName = u.FirstName,
LastName = u.LastName,
DocumentCount = u.Documents.Count
}).ToPagedList(page, 10);
var userprofilemodel2 =
(from u in db.UserProfiles
where u.UserId == 18
orderby u.FirstName, u.LastName
select new UserListViewModel
{
UserId = u.UserId,
UserName = u.UserName,
FirstName = u.FirstName,
LastName = u.LastName,
DocumentCount = u.Documents.Count
}).ToPagedList(page, 10);
userprofilemodel1.Concat(userprofilemodel2);
It seems like this should do it:
var userprofilemodel1 =
(from u in db.UserProfiles
where u.UserId == 1 || u.UserId == 18
orderby u.FirstName, u.LastName
select new UserListViewModel
{
UserId = u.UserId,
UserName = u.UserName,
FirstName = u.FirstName,
LastName = u.LastName,
DocumentCount = u.Documents.Count
}).ToPagedList(page, 10);
If you want/need to leave it as two separate queries but are trying to concatenate the results, then you need to realize that Concat returns a concatenated list - it does not modify either of the existing lists:
var mergedModel = userprofilemodel1.Concat(userprofilemodel2);

multiple JOIN + SUM() query in LINQ -> can't loop in view

I'm trying to translate an SQL query into LINQ, but after numerous attempts, I'm still not there... Can anyone help ?
This is my working SQL statement
SELECT Users.email, SUM(Skills.level) AS SkillLevel
FROM Skills INNER JOIN
SkillsPerUser ON Skills.pk_skill_id = SkillsPerUser.fk_skill_id INNER JOIN
Users ON SkillsPerUser.fk_user_id = Users.pk_userid
GROUP BY Users.email
ORDER BY SkillLevel DESC
This is what I came up with so far, but it lacks a sum() where I hard coded the number 3, that should be the sum of Skills.level:
var allSkillsPerUser = from u in dc.Users
join spu in dc.SkillsPerUsers on u.pk_userid equals spu.fk_user_id
join s in dc.Skills on spu.fk_skill_id equals s.pk_skill_id
select new { Email = u.email, Level = s.level } into su
group su by su.Email into gsu
select new { Email = gsu.Key, SkillLevel = gsu.Sum(su => su.Level) };
ViewBag.spu = allSkillsPerUser.ToList();
The view bag gives the following error (Email can't be found, while in the variables below you can see that they do exist...):
context.Skills
.Join(context.SkillsPerUser, s => s.pk_skill_id, spu => spu.fk_skill_id, (s, spu) => new { Skill = s, SkillToUser = spu })
.Join(context.Users, sspu => sspu.SkillToUser.fk_userId, u => u.pk_userid, (sspu, u) => new { Email = u.Email, SkillLevel = sspu.Skill.level })
.GroupBy(su => su.Email)
.Select(g => new { Email = g.Key, SkillLevel= g.Sum(su => su.Level) })
.OrderByDescending(g => g.SkillLevel)
It's a bit simpler if you have navigation properties set up on your entities:
context.SkillsPerUser
.Select(spu => new { Email = spu.User.email, Level = spu.Skill.level }) // guessing at the navigation property names here
.GroupBy(su => su.Email)
.Select(g => new { Email = g.Key, SkillLevel = g.Sum(su => su.Level) })
.OrderByDescending(g => g.SkillLevel)
Or, using the query syntax
from u in dc.Users
join spu in dc.SkillsPerUsers on u.pk_userid equals spu.fk_user_id
join s in dc.Skills on spu.fk_skill_id equals s.pk_skill_id
select new { Email = u.email, Level = s.level } into su
group su by su.Email into gsu
select new { Email = gsu.Key, SkillLevel = gsu.Sum(su => su.Level) }
To order by the sum you can do this:
from u in dc.Users
join spu in dc.SkillsPerUsers on u.pk_userid equals spu.fk_user_id
join s in dc.Skills on spu.fk_skill_id equals s.pk_skill_id
select new { Email = u.email, Level = s.level } into su
group su by su.Email into gsu
select new { Email = gsu.Key, SkillLevel = gsu.Sum(su => su.Level) } into userSkills
orderby userSkills.SkillLevel descending

Resources