Query SQL to Lambda Expression - c#

I hope you can help me with this.
I want to convert this query from SQL in a lambda expression in C#:
select
a.Descripcion
from
pb.MantenimientosTipos a
where
a.activo = 1 and
a.idSegmento in (select b.idSegmento
from pb.MaquinasRelSegm b
where b.idMaquina = 67)
How can I do this?
I have two selectList, "a" and "b", the selectList "a" is list from table b filter by a parameter and the selectList "b" is a list from table a filter by SelectList "a"
private SelectList a (bool agregarTodo = false)
{
var segmentos = pb.MaquinasRelSegm.Where(x => x.idMaquina == MaquinaId).Select(x => x.Segmentos).ToList();
if (agregarTodo)
{
segmentos.Add(new PB.Domain.Entities.Segmentos { idSegmento = 0, Descripcion = "Todos" });
}
return new SelectList(segmentos, "idSegmento", "Descripcion");
}
private SelectList b (byte idSegmento, bool agregarTodo = false)
{
var tipos = pb.MantenimientosTipos.Where(x => x.idSegmento == idSegmento && x.Activo).ToList();
if (agregarTodo)
{
tipos.Insert(0, new PB.Domain.Entities.MantenimientosTipos { idTipoMTTO = 0, Descripcion = "Todo" });
}
return new SelectList(tipos, "idTipoMTTO", "Descripcion")
}
I want to put only one selectList with this SQL query
This is the relationship in SQL SERVER
https://drive.google.com/file/d/0BzpCEYwGGpogRGRaOVNXTDBrTWc/view?usp=sharing

Thanks for the diagram.
try to use this (assuming that pb is the EF context):
var segmentoIds = pb.MaquinasRelSegm
.Where(a => a.idMaquina == 67)
.Select(a => a.idSegmento)
.ToList();
var description = pb.MantenimientosTipos
.Where(a => a.Activo && segmentoIds.Contains(a.idSegmento))
.Select(a => a.Description);

Related

Isolating where clause in LINQ C#

I have the following code
RoseFlowersData = (from c in dbContext.ClientFirst
where c.RoseFlower.Id == Id
select new FlowerDTO
{
flowerId = c.Id,
flowerCatergory = c.flowerCatergory
}),
AsterFlowerData = (from c in dbContext.ClientFirst
where c.AsterFlower.Id == Id
select new FlowerDTO
{
flowerId = c.Id,
flowerCatergory = c.flowerCatergory
}),
in both, the only difference is the where clause (where c.RoseFlower.Id == Id; where c.AsterFlower.Id == Id)
I want to use following function to get me data based on different flower type (like RoseFlower, AsterFlower etc)
private IQueryable<FlowerDTO> GetFlowerData(int flowerId, <What should I pass here?>)
{
var data = (from c in dbContext.ClientFirst
where c.RoseFlower.Id == flowerId
select new FlowerDTO
{
flowerId = c.Id,
flowerCatergory = c.flowerCatergory
});
return data;
}
I am confused on how I can use this function for both and further flower types. I have tried looking for solutions to isolate the where clause but after hours of search, I have not been able to find a solution. Maybe I am not searching for the right thing.
Thank you for your time and help
If you convert your LINQ to a fluid syntax using the LINQ extension methods instead:
private IQueryable<FlowerDTO> GetFlowerData(Predicate<Flower> where)
{
var data = dbContext.ClientFirst
.Where(where)
.Select(c => new FlowerDTO
{
flowerId = c.Id,
flowerCatergory = c.flowerCatergory
});
return data;
}
Then call your method:
GetFlowerData(f => f.Id == desiredFlowerId && f.FlowerType == "RoseFlower");
I agree with #Andrew H, but instead of passing Predicate<Flower> where as a parameter, I did passing only the Id and FlowerType, just to have less repetitions and better to maintenance:
private IQueryable<FlowerDTO> GetFlowerData(int id, string flowerType)
{
var data = dbContext.ClientFirst
.Where(f => f.Id == Id && f.FlowerType == flowerType)
.Select(c => new FlowerDTO
{
flowerId = c.Id,
flowerCatergory = c.flowerCatergory
});
return data;
}
and then:
GetFlowerData(1, "RoseFlower");
GetFlowerData(2, "AsterFlower");
Just ideas to you create your own function. Have fun.

Execute query using LINQ or EF to fetch records from multiple tables

I've been searching for a while now. But all the solutions seems to be different than what I expect.
So this is my query in SQL:-
Select * from
(
select Name,Description Descr from CourseTbl
union all
select MainDesc Name,MainDesc Descr from CoursedescTbl
union all
select SubHeading Name,SubDesc Descr from CourseSubDesc
union all
select Name,Descr as Descr from InternTbl
)A where A.Name like '%D%' or A.Descr like '%D%'
I want to execute the above query using LINQ or EF. and return the list in Json format. So I tried many failed attempts and this is one of them:-
public JsonResult SearchDetail()
{
string SearchKey = Request.Form["SearchName"].ToString();
IEnumerable<SearchList> QueryResult;
using (EBContext db = new EBContext())
{
try
{
QueryResult =
(from x in db.Courses
select new { A = x.Name, B = x.Description })
.Concat(from y in db.CourseDesc
select new { A = y.MainHeading, B = y.MainDesc })
.Concat(from z in db.CourseSubDesc
select new { A = z.SubDesc, B = z.SubHeading })
.Concat(from w in db.Interns
select new { A = w.Name, B = w.Descr })
.ToList();
}
catch (Exception ex)
{
return new JsonResult
{
Data = ex.Message,
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
}
return new JsonResult
{
Data = QueryResult,
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
}
}
And my SearchList Class is like this:-
public class SearchList
{
public string Name { get; set; }
public string Descr { get; set; }
}
I'm not able to put the where clause in linq query which will search in all table.
I'm getting error when I assign queryresult to my ef query. It says cannot cast to Innumerable.
Thanks in Advance.
Could you explain more on the error you are getting?
Also, have you tried using .Union() in linq?
QueryResult = db.Courses.Select(x=> new { A = x.Name, B= x.Description})
.Union(db.CourseDesc.Select(y=> new {A = y.MainHeading, B = y.MainDesc })
.Union( //so on
.ToList(); //this isn't necessary
Edit: There are two ways to input where clause, either with each search, or at the end:
QueryResult = db.Courses.Where(x=>x.Name == "Name").Select(x=> new { A = x.Name, B= x.Description})
.Union(db.CourseDesc.Where(y=>y.MainHeading == "Name").Select(y=> new {A = y.MainHeading, B = y.MainDesc })
.Union( //so on
.ToList();
Or:
QueryResult = db.Courses.Where(x=>x.Name == "Name").Select(x=> new { A = x.Name, B= x.Description})
.Union(db.CourseDesc.Where(y=>y.MainHeading == "Name").Select(y=> new {A = y.MainHeading, B = y.MainDesc })
.Union( //so on
//Where can go either before or after .ToList
.Where(item=>item.A == "Name")
.ToList();
You did not say what error/exception you are getting. But your QueryResult is of type IEnumerable<SearchList> and you appear to be assigning it an enumerable of anonymous type { A, B }.
Try this:
QueryResult = (from x in db.Courses
select new SearchList { Name = x.Name, Descr = x.Description })
.Concat(...)
.ToList();
Or
QueryResult = db.Courses.Select(x => new SearchList
{ Name = x.Name, Descr = x.Description})
.Concat(...)
.ToList();
UPDATE
Your #2 issue will be fixed if you changed your select to new up a SearchList as I did above, instead of new-ing an anonymous type.
As for your issue #1, you should insert the Where() before your Select():
result1 = db.Courses
.Where(x => x.Name.Contains('D') || x.Description.Contains('D'))
.Select(x => new SearchList { Name = x.Name, Descr = x.Description});
result2 = db.CourseDesc
.Where(y => y.MainHeading.Contains('D') || y.MainDesc.Contains('D'))
.Select(y => new SearchList { Name = y.MainHeading, Descr = y.MainDesc});
result3 = db.CourseSubDesc
.Where(...)
.Select(...);
QueryResult = result1.Concat(result2).Concat(result3).ToList();
Doing Where() as part of the query on each table is important so you do not fetch all records from that table, unlike if you do the Where() after Concat(). Also note that Concat() may throw an ArgumentNullException.
Take the lists Separately and query and concat
check this example
List<string> a = new List<string>() { "a", "b", "c" };
List<string> b = new List<string>() { "ab", "bb", "cb" };
IEnumerable<SearchList> QueryResult =
a.Where(x => x.Contains("a")).Select(x => new SearchList() { Name = x, Descr = x })
.Concat(b.Where(x => x.Contains("a")).Select(x => new SearchList() { Name = x, Descr = x }));

Entity Framework building Where clause on the fly using Expression

Using Entity Framework C# and have this query, I need the part where it says:
where x.Login_Status == "Submitted"
to be dynamic. There are different cases it could be "Submitted" or null or something else and instead of writing multiple if statement with different queries in it, want to have a Predicate in a where clause.
status = (from x in ctx.table
where x.Login_Status == "Submitted"
orderby x.SUB_DATE descending
select new Model_Table()
{
Id = x.ID,
Name = x.NAME,
Code = x.Code,
DateSubmitted = x.SUB_DATE
}).ToList<Model_Table>();
Is that possible?
Solution:
Inside the if statement when more parameters encountered use this
where_expression = x => x.Login_Status == "Submitted" || x.Login_Status == null;
Here is a complete code that worked for me, anything between square brackets replace to suit your code:
Expression<Func<[Replace with your Entity], bool>> where_submitted = x => x.Login_Status == "Submitted";
// Check if all selected
if (CheckBox_Show_All_Submitted.Checked)
{
where_submitted = x => x.Login_Status == "Submitted" || x.Login_Status == null;
}
status =
ctx.[Replace with your Entity Table]
.Where(where_submitted)
.OrderByDescending(x => x.SUB_DATE)
.Select(x => new Model_Table
{
Id = x.ID,
Name = x.NAME,
Code = x.Code,
DateSubmitted = x.SUB_DATE
}).ToList<Model_Table>();
You need an Expression<Func<Entity,bool>>, not a Predicate<Entity>. The difference is that a predicate is a compiled delegate, and an expression is code as data and thus can be translated to SQL.
Here is an example:
//You can have this expression have different values based on your logic
Expression<Func<Entity,bool>> where_expression = x => x.Login_Status == "Submitted";
var query =
ctx.Table
.Where(where_expression)
.OrderByDescending(x => x.SUB_DATE)
.Select(x => new Model_Table())
{
Id = x.ID,
Name = x.NAME,
Code = x.Code,
DateSubmitted = x.SUB_DATE
}).ToList();
Please note that you need to replace Entity with the name of the real class.
Create an extension method for IQueryable like this:
public static class MethodExtensions{
public static IEnumerable<Model_Table> Query(this IQueryable<TEntity> source, string data){
return (from x in source
where x.Login_Status == data
orderby x.SUB_DATE descending
select new Model_Table()
{
Id = x.ID,
Name = x.NAME,
Code = x.Code,
DateSubmitted = x.SUB_DATE
}).ToList<Model_Table>();
}
}
Now you can use it like this:
var result = ctx.table.Query("somethingelse");

Lambda expression where id in list of ids

I have 2 lists
var listquestionold = db.tblExamQuetions.Where(p => p.QuetionExamId == oldexamid).ToList();
var listquestionnew = listquestionnew = db.tblExamQuetions.Where(p => p.QuetionExamId == examid ).ToList();
List<tblExamQuestionAnswers> listanswers = new List<tblExamQuestionAnswers>();
How can I get answers where questionId is in listquestionold:
listanswers =db.tblanswers.where(p=> p.ExamQuestionId exists in listquestionold ?
It's easy with Contains method of the List:
var listquestionold = db.tblExamQuetions.Where(p => p.QuetionExamId == oldexamid).ToList();
var listanswers = db.tblanswers.Where(w => listquestionold.Contains(w.ExamQuestionId)).ToList();

Assign values from one list to another using LINQ

Hello I have a little problem with assigning property values from one lists items to anothers. I know i could solve it "the old way" by iterating through both lists etc. but I am looking for more elegant solution using LINQ.
Let's start with the code ...
class SourceType
{
public int Id;
public string Name;
// other properties
}
class DestinationType
{
public int Id;
public string Name;
// other properties
}
List<SourceType> sourceList = new List<SourceType>();
sourceList.Add(new SourceType { Id = 1, Name = "1111" });
sourceList.Add(new SourceType { Id = 2, Name = "2222" });
sourceList.Add(new SourceType { Id = 3, Name = "3333" });
sourceList.Add(new SourceType { Id = 5, Name = "5555" });
List<DestinationType> destinationList = new List<DestinationType>();
destinationList.Add(new DestinationType { Id = 1, Name = null });
destinationList.Add(new DestinationType { Id = 2, Name = null });
destinationList.Add(new DestinationType { Id = 3, Name = null });
destinationList.Add(new DestinationType { Id = 4, Name = null });
I would like to achieve the following:
destinationList should be filled with Names of corresponding entries (by Id) in sourceList
destinationList should not contain entries that are not present in both lists at once (eg. Id: 4,5 should be eliminated) - something like inner join
I would like to avoid creating new destinationList with updated entries because both lists already exist and are very large,
so no "convert" or "select new".
In the end destinationList should contain:
1 "1111"
2 "2222"
3 "3333"
Is there some kind of elegant (one line Lambda? ;) solution to this using LINQ ?
Any help will be greatly appreciated! Thanks!
I would just build up a dictionary and use that:
Dictionary<int, string> map = sourceList.ToDictionary(x => x.Id, x => x.Name);
foreach (var item in destinationList)
if (map.ContainsKey(item.Id))
item.Name = map[item.Id];
destinationList.RemoveAll(x=> x.Name == null);
Hope this will your desired result. First join two list based on key(Id) and then set property value from sourceList.
var result = destinationList.Join(sourceList, d => d.Id, s => s.Id, (d, s) =>
{
d.Name = s.Name;
return d;
}).ToList();
Barring the last requirement of "avoid creating new destinationList" this should work
var newList = destinationList.Join(sourceList, d => d.Id, s => s.Id, (d, s) => s);
To take care of "avoid creating new destinationList", below can be used, which is not any different than looping thru whole list, except that it probably is less verbose.
destinationList.ForEach(d => {
var si = sourceList
.Where(s => s.Id == d.Id)
.FirstOrDefault();
d.Name = si != null ? si.Name : "";
});
destinationList.RemoveAll(d => string.IsNullOrEmpty(d.Name));
Frankly, this is the simplest:
var dictionary = sourceList.ToDictionary(x => x.Id, x => x.Name);
foreach(var item in desitnationList) {
if(dictionary.ContainsKey(item.Id)) {
item.Name = dictionary[item.Id];
}
}
destinationList = destinationList.Where(x => x.Name != null).ToList();
You could do something ugly with Join but I wouldn't bother.
I hope this will be useful for you. At the end, destinationList has the correct data, without creating any new list of any kind.
destinationList.ForEach(x =>
{
SourceType newSource = sourceList.Find(s=>s.Id == x.Id);
if (newSource == null)
{
destinationList.Remove(destinationList.Find(d => d.Id == x.Id));
}
else
{
x.Name = newSource.Name;
}
});

Categories