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.
Related
I've been using linq for a little while now but haven't come across this situation anywhere and my google-fu let me down.
Basically I have two data sets which I did not define and now have to use to return data.
class Header
{
string COMPANY_CODE
string REFERENCE_NBR
string REFERENCE_DUPLICATE
...
}
class Line
{
string COMPANY_CODE
string REFERENCE_NBR
string REFERENCE_DUPLICATE
string STOCK_CODE
string DESCRIPTION
...
}
From a database perspective they join like this
select *
from Header
inner join Line
on header.COMPANY_CODE = Line.COMPANY_CODE
and header.REFERENCE_NBR = Line.REFERNCE_NBR
and header.REFERENCE_DUPLICATE = LINE.REFERENCE_DUPLICATE
and have a 1:Many relationship.
I'm implementing a search feature for a listing that is meant to find any Lines that with a value in STOCK_CODE or DESCRIPTION that matches a given search term. I have seen a couple of methods of joining using a linq query but because of the multiple join conditions I'm a bit lost and have not found any examples of what I'm trying to do.
If I were to write the statement I am trying to get in lamda/linq in SQL it would be:
declare #searchtxt nvarchar(max) = 'test'
Select *
from header h
where exists (
select *
from Line l
where
(
l.stock_code like '%'+#searchtxt+'%'
or l.description like '%'+#searchtxt+'%'
)
and h.COMPANY_CODE = l.COMPANY_CODE
and h.REFERENCE_NBR = l.REFERENCE_NBR
and h.REFERENCE_DUPLICATE = l.REFERENCE_DUPLICATE
)
Any help would be appreciated!
Perhaps, this?
var result = header.Where(h =>
Line.Any(l => (l.stock_code.Contains(searchtxt)
|| l.description.Contains(searchtxt))
&& h.COMPANY_CODE == l.COMPANY_CODE
&& h.REFERENCE_NBR == l.REFERENCE_NBR
&& h.REFERENCE_DUPLICATE == l.REFERENCE_DUPLICATE));
This is a traditional LINQ query for better understanding,
string searchtext = "";
var result = (from h in context.Headers
join l in context.Lines on new { h.COMPANY_CODE, h.REFERENCE_DUPLICATE, h.REFERENCE_NBR } equals new { l.COMPANY_CODE, l.REFERENCE_DUPLICATE, l.REFERENCE_NBR }
where l.STOCK_CODE.Contains(searchtext) || l.DESCRIPTION.Contains(searchtext)
select new
{
COMPANY_CODE = h.COMPANY_CODE,
STOCK_CODE = l.STOCK_CODE
//You can select more fields from "h" and "l"
}).ToList();
Edit:
string searchtext = "";
var result = (from h in context.Headers
join l in context.Lines on new { h.COMPANY_CODE, h.REFERENCE_DUPLICATE, h.REFERENCE_NBR } equals new { l.COMPANY_CODE, l.REFERENCE_DUPLICATE, l.REFERENCE_NBR }
where l.STOCK_CODE.Contains(searchtext) || l.DESCRIPTION.Contains(searchtext)
select h
)
.GroupBy(x => new { x.COMPANY_CODE, x.REFERENCE_DUPLICATE, x.REFERENCE_NBR })
.Select(x => x.First())
.ToList();
db.Header.Join(
db.Line,
h => new { h.COMPANY_CODE, h.REFERENCE_NBR, h.REFERENCE_DUPLICATE },
l => new { l.COMPANY_CODE, l.REFERENCE_NBR, l.REFERENCE_DUPLICATE },
(h, l) => new
{
Header_COMPANY_CODE = h.COMPANY_CODE,
Header_REFERENCE_NBR = h.REFERENCE_NBR,
Header_REFERENCE_DUPLICATE = h.REFERENCE_DUPLICATE,
Line_Company_Code = l.COMPANY_CODE,
Line_REFERENCE_NBR = l.REFERENCE_NBR,
Line_REFERENCE_DUPLICATE = l.REFERENCE_DUPLICATE,
Line_STOCK_CODE = l.STOCK_CODE,
Line_DESCRIPTION = l.DESCRIPTION
}
)
.Where(w => w.Line_STOCK_CODE.Contains(searchText) || w.Line_DESCRIPTION.Contains(searchText))
.ToList();
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 }));
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);
Table 1 called Category contains 70 records
Table 2 called FilterCategorys contains 0 records (currently).
my lambda join, I want to pull only records that don't match, so in this case I expect to get 70 records back. Here's my incorrect Lambda:
var filteredList = categorys
.Join(filterCategorys,
x => x.Id,
y => y.CategoryId,
(x, y) => new { catgeory = x, filter = y })
.Where(xy => xy.catgeory.Id != xy.filter.CategoryId)
.Select(xy => new Category()
{
Name = xy.catgeory.Name,
Id = xy.catgeory.Id,
ParentCategoryId = xy.catgeory.ParentCategoryId
})
.ToList();
Whats the correct syntax I need here?
Not sure if you have a requirement of using lambdas (rather than query syntax), but I prefer query syntax for statements that have outer joins.
This should be equivalent:
var filteredList = (
from c in Categorys
join fc in FilterCategorys on c.Id equals fc.CategoryId into outer
from o in outer.DefaultIfEmpty()
select new
{
Category = new Category
{
Name = c.Name,
Id = c.Id,
ParentCategoryId = c.ParentCategoryId
},
Exists = (o != null)
})
.Where(c => !c.Exists)
.Select(c => c.Category);
If you want to do it in purely lambda:
var match = categorys.Join(filterCategorys, x => x.Id, y => y.CategoryId, (x, y) => new { Id = x.Id });
var filteredList = categorys.Where(x => !match.Contains(new {Id = x.Id}));
I haven't measured the performance of this, but for 70 records, optimization is not an issue.
Well I came up with a solution that takes away the need for the join.
var currentIds = filterCategorys.Select(x => x.Id).ToList();
var filteredList = categorys.Where(x => !currentIds.Contains(x.Id));
very similar to #Zoff Dino answer, not sure about performance, maybe someone would like to check.
Try this:
var categories= ...
var filteredCategories=...
var allExceptFiltered = categories.Except(filteredCategories, new CategoryComparer()).ToList();
If you don't provide a custom Comparer that framework has no way of knowing that 2 Category objects are the same(even if they have the same ID),it just thinks that they are different objects (it checks for reference equality )
so you must add this class to your project:
public class CategoryComparer: IEqualityComparer<Category>
{
public bool Equals(Category x, Category y)
{
if (x == null && y == null)
return true;
if (x == null)
return false;
if (y == null)
return false;
return x.CategoryId.GetHashCode() == y.CategoryId.GetHashCode();
}
public int GetHashCode(Category obj)
{
return obj.CategoryId.GetHashCode();
}
}
update
Also check out Wyatt Earp's answer,it is very useful to know how to do an outer join
update 2
Your problem is the Join method.
The Where clause is "called" after the join.so after you have joined the listed based on the ID you select those which have different IDs,that's why you get no resuts
Could you draw bracket and it should work.
....Where(xy => (xy.catgeory.Id != xy.filter.CategoryId))
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;
}
});