I have a line like so:
var lstOfIds = db.TBL_AssocIncidentSpecialCat
.Where(x => x.IncidentId == incidentVm.ID)
.Select(t => t.SpecialCategoriesId)
.ToList();
This line gathers me a list of of the SpecialCategoriesIds. Then I have to do this:
incidentVm.LstSpecialCategories = db.TBL_SpecialCategories
.Where(x => lstOfIds.Contains(x.Id))
.Select(t => t.SpecialCategory)
.ToList();
Is there a way to combine these two lines into one? Even though it's only two lines of code.. I feel as though having to grab the Ids first then having to grab the associated property based on the Id is just an extra step and could be shortened to just one line. But I may be wrong.
Any help is appreciated.
UPDATE
incidentVm.LstSpecialCategories = db.TBL_AssocIncidentSpecialCat
.Where(x => x.IncidentId == incidentVm.ID)
.Join(
db.TBL_SpecialCategories,
x => new{Id = x.SpecialCategoriesId},
t => new{Id = t.Id},
(x,t) => {return t.SpecialCategory}
);
I am getting red squiggly under last part in Join:
A lambda expression with a statement body cannot be converted to an expression tree
You can combine the two lines using Join. Something like,
var result = db.TBL_AssocIncidentSpecialCat
.Join(
db.TBL_SpecialCategories,
ais => new { Id = ais.IncidentId },
sc => new { Id = sc.Id },
(ais, sc) => { return sc; }
)
.ToList();
C# Fiddle for this.
Update with Where Clause: You should use your Where condition after the Join.
var result = db.TBL_AssocIncidentSpecialCat
.Join(
db.TBL_SpecialCategories,
ais => new { Id = ais.IncidentId },
sc => new { Id = sc.Id },
(ais, sc) => new { ais = ais, sc = sc }
)
.Where(x => x.ais.IncidentId == 1)
.Select(y => y.sc)
.ToList();
You can try a LINQ query-style join:
incidentVm.LstSpecialCategories = (from aispc in db.TBL_AssocIncidentSpecialCat
join spc in db.TBL_SpecialCategories
on aispc.SpecialCategoriesId equals lspc.Id
where aispc.IncidentId == incidentVm.ID
select lspc.SpecialCategory).ToList();
I was able to figure this out with the help of some answers and me testing it on my own. Here is my solution:
incidentVm.LstSpecialCategories = db.TBL_AssocIncidentSpecialCat
.Where(t => t.IncidentId == incidentVm.ID)
.Join(db.TBL_SpecialCategories,
ik => ik.SpecialCategoriesId,
ok => ok.Id,
(ik, ok) => ok.SpecialCategory
)
.ToList();
Thank you for all of your help.
Related
Consider the following LINQ statements:
var model = getModel();
// apptId is passed in, not the order, so get the related order id
var order = (model.getMyData
.Where(x => x.ApptId == apptId)
.Select(y => y.OrderId));
var orderId = 0;
var orderId = order.LastOrDefault();
// see if more than one appt is associated to the order
var apptOrders = (model.getMyData
.Where(x => x.OrderId == orderId)
.Select(y => new { y.OrderId, y.AppointmentsId }));
This code works as expected, but I could not help but think that there is a more efficient way to accomplish the goal ( one call to the db ).
Is there a way to combine the two LINQ statements above into one? For this question please assume I need to use LINQ.
You can use GroupBy method to group all orders by OrderId. After applying LastOrDefault and ToList will give you the same result which you get from above code.
Here is a sample code:
var apptOrders = model.getMyData
.Where(x => x.ApptId == apptId)
.GroupBy(s => s.OrderId)
.LastOrDefault().ToList();
Entity Framework can't translate LastOrDefault, but it can handle Contains with sub-queries, so lookup the OrderId as a query and filter the orders by that:
// apptId is passed in, not the order, so get the related order id
var orderId = model.getMyData
.Where(x => x.ApptId == apptId)
.Select(y => y.OrderId);
// see if more than one appt is associated to the order
var apptOrders = model.getMyData
.Where(a => orderId.Contains(a.OrderId))
.Select(a => a.ApptId);
It seems like this is all you need:
var apptOrders =
model
.getMyData
.Where(x => x.ApptId == apptId)
.Select(y => new { y.OrderId, y.AppointmentsId });
I'm trying to iterate from a list with Linq in order to create and return a model, with contains a list of item and a quantity of total items.
The object that must be returned is as following:
public class ListeArticlesModel
{
public List<TuileArticleModel> Items { get; set; }
public int Quantity { get; set; }
}
I'm currently stuck with this :
result.Actualites = tousLesArticlesFromDb
.ToList()
.Where(
a => a.GetPropertyValue<IEnumerable<IPublishedContent>>("ficheArticle_typeDeContenu")
.FirstOrDefault()?.Name == #EnumResources.TypeDeContenu_Actualites)
.OrderBy(a => a.CreateDate)
.Take(criteriaModel.NbrItemsParPage)
.Select(
a => new ListeArticlesModel
{
Items = new List<TuileArticleModel>
{
// returns a TuileArticleModel
getItem(a)
},
})
.FirstOrDefault();
This is not what I want. If I remove the .FirstOrDefault() I get an IEnumerable
I know I am missing something. I'm building a new ListeArticleModel for each "a" item and then I just take the first one built but I don't see how to get out of here...
(ps : I graduated a few weeks ago. I am new to C#. I know it may be basics. I am trying to learn them :D)
I tried this:
var actus = tousLesArticlesFromDb
.ToList()
.Where(
a => a.GetPropertyValue<IEnumerable<IPublishedContent>>("ficheArticle_typeDeContenu")
.FirstOrDefault()?.Name == #EnumResources.TypeDeContenu_Actualites)
.OrderBy(a => a.CreateDate)
.Take(criteriaModel.NbrItemsParPage);
This gives me an IEnumerable (using umbraco here) which contains the criteriaModel.NbrItemsParPage IPublishedContent items of type "Actualites" that I want...
Now, for each I'd like to create a new TuileArticleModel to feed the Items proptery (a List<TuileArticleModel>) of my result.Actualites...
EDIT :
I think I just resolved my problem by exposing it to you guys, and reading the comments. So I did this :
var actus = tousLesArticlesFromDb
.ToList()
.Where(
a => a.GetPropertyValue<IEnumerable<IPublishedContent>>("ficheArticle_typeDeContenu")
.FirstOrDefault()?.Name == #EnumResources.TypeDeContenu_Actualites)
.Take(criteriaModel.NbrItemsParPage);
result.Actualites.Items = actus.Select(a => {return getItem(a); }).ToList();
or in one statement :
result.Actualites = new ListeArticlesModel
{
Items = tousLesArticlesFromDb
.Where
(
a => a.GetPropertyValue<IEnumerable<IPublishedContent>>("ficheArticle_typeDeContenu")
.FirstOrDefault()?.Name == #EnumResources.TypeDeContenu_Actualites
)
.OrderBy(a => a.CreateDate)
.Take(criteriaModel.NbrItemsParPage)
.Select(a => { return getItem(a); }).ToList(),
};
Get the resultset first:
var results = tousLesArticlesFromDb
.Where
(
a => a.GetPropertyValue<IEnumerable<IPublishedContent>>("ficheArticle_typeDeContenu")
.FirstOrDefault()?.Name == #EnumResources.TypeDeContenu_Actualites
)
.OrderBy(a => a.CreateDate)
.Take(criteriaModel.NbrItemsParPage);
Then pass it into the new object:
result.Actualites = new ListeArticlesModel
{
Items = results.ToList()
};
Or, if you want to do it all in one statement:
result.Actualites = new ListeArticlesModel
{
Items = tousLesArticlesFromDb
.Where
(
a => a.GetPropertyValue<IEnumerable<IPublishedContent>>("ficheArticle_typeDeContenu")
.FirstOrDefault()?.Name == #EnumResources.TypeDeContenu_Actualites
)
.OrderBy(a => a.CreateDate)
.Take(criteriaModel.NbrItemsParPage);
.ToList()
};
.ToList()
instead of
.FirstOrDefault()
Another thing to note is
tousLesArticlesFromDb
.Where( *** )
.OrderBy(a => a.CreateDate)
.Take(criteriaModel.NbrItemsParPage)
.Select(
a => new ListeArticlesModel
{
Items = new List<TuileArticleModel>
{
// returns a TuileArticleModel
getItem(a)
},
})
This will return a IQueryable, no processing has been done yet, you've just created the query for it.
Calling .ToList() will execute the IQueryable and return the result as a list.
I'm trying to select multiple columns not in a group by using linq - c#.
Using linq, I'm trying to group by ISNULL(fieldOne,''),ISNULL(fieldTo,'') and then select field_One, field_Two, field_Three for each group. So for each row that the group by would return, I want to see numerous rows.
So far I have the following, but can't seem to select all the needed columns.
var xy = tableQueryable.Where(
!string.IsNullOrEmpty(cust.field_One)
|| ! string.IsNullOrEmpty(ust.field_Two)
).GroupBy(cust=> new { field_One= cust.field_One ?? string.Empty, field_Tow = cust.field_Two ?? string.Empty}).Where(g=>g.Count()>1).AsQueryable();
Can somebody help pls?
You are pretty much there - all you are missing is a Select from the group:
var xy = tableQueryable
.Where(!string.IsNullOrEmpty(cust.first_name) || ! string.IsNullOrEmpty(ust.lastName))
.GroupBy(cust=> new { first_name = cust.first_name ?? string.Empty, last_name = cust.last_name ?? string.Empty})
.Where(g=>g.Count()>1)
.ToList() // Try to work around the cross-apply issue
.SelectMany(g => g.Select(cust => new {
Id = cust.Id
, cust.FirstName
, cust.LastName
, cust.RepId
}));
Select from each group does the projection of the fields that you want, while SelectMany dumps all the results into a flat list.
Would this work for you?
var groupsWithDuplicates = tableQueryable
.Where(c => !string.IsNullOrWhiteSpace(c.first_name) || !string.IsNullOrWhiteSpace(c.last_name))
.GroupBy(c => new { FirstName = c.first_name ?? "", LastName = c.last_name ?? "" })
.Where(group => group.Count() > 1) // Only keep groups with more than one item
.ToList();
var duplicates = groupsWithDuplicates
.SelectMany(g => g) // Flatten out groups into a single collection
.Select(c => new { c.first_name, c.last_name, c.customer_rep_id });
For me I have used following query to do the filter Customer and get the customer records group by the JobFunction. In my case the issue get resolved after adding the .AsEnumerable() after the where solve the problem.
var query = _context.Customer
.Where(x => x.JobTitle.ToUpper().Contains(searchText.ToUpper())).AsEnumerable()
.GroupBy(item => item.JobFunction,
(key, group) => new {
JobFunction = key,
CustomerRecords = group.ToList().Select(c => c).ToList()
})
.ToList();
I have a SQL command that I am trying to convert to a LINQ to SQL command, but am having difficulties.
My SQL command follows:
SELECT purchs.iclientid, ifeatureid, AddnlOptionList FROM purchs
WHERE AddnlOptionList <> ''
GROUP BY purchs.iclientid, ifeatureid, AddnlOptionList
HAVING (SUM(noptions) > 0)
I've managed to get this far following examples:
var q =
from purchs in db.Purchases
group q by purchs.noptions into g
where purchs.AddnlOptionList != ""
&& g.Sum(x => x.noptions) > 0
select q;
However, I seem to be stuck on group q with the following two errors:
Cannot use local variable 'q' before it is declared
Cannot convert lambda expression to type 'System.Collections.Generic.IEqualityComparer<decimal?> because it is not a delegate type
An example from here says that this should work, although it uses a join, and I am not. Any help would be appreciated.
SOLUTION
I had to modify Xiaoy312's code a little bit to get what I wanted, so I figured I would post it here in hopes that it might help someone in the future. Thank you #Xiaoy312 for the help.
var updates = db.Purchases
.Where(p => p.AddnlOptionList != "")
.GroupBy(p => new { p.iclientid, p.ifeatureid, p.AddnlOptionList })
.Where(g => g.Sum(p => p.noptions) > 0)
.Select(g => g.Key);
You can't put both the WHERE and HAVING clause into a single where. I'm less familiar with the other syntax, so here is the method syntax one :
var results = db.Purchases
.Where(p => p.AddnlOptionList != "")
.GroupBy(p => new { p.notions, p.iclientid, p.ifeatureid })
.Where(g => g.Sum(p => p.notions) > 0)
.SelectMany(g => g)
EDIT: converted to Linq syntax.
var results = from p in db.Purchases
where p.AddnlOptionList != ""
group p by new { p.notions, p.iclientid, p.ifeatureid } into g
where g => g.Sum(p => p.notions) > 0
from p in g
select p;
EDIT: I've miss read the sql command. It meant to only pull the groups, not every item in each group.
// method syntax
db.Purchases
.Where(p => p.AddnlOptionList != "")
.GroupBy(p => new { p.notions, p.iclientid, p.ifeatureid })
.Where(g => g.Sum(p => p.notions) > 0)
.Select(g => g.Key)
// query syntax
from p in db.Purchases
where p.AddnlOptionList != ""
group p by new { p.notions, p.iclientid, p.ifeatureid } into g
where g.Sum(p => p.notions) > 0
select new { g.Key.notions, g.Key.iclientid, g.Key.ifeatureid };
I have an sql table with columns Name, Category, Location. I am using Elastic Search with NEST. my query like this:
var result = client.Search<Models.Search.Poll>(s => s.Query(q => q.Fuzzy(f => f.OnField(p => p.Name).Value(query))))));
So if there is a record with name = "We are here" and user search "are" , it returns result.
Now I need to add two more parameters category and location to this query:
so I made it like this:
var result = client.Search<Models.Search.Poll>(s => s.Query(q => q.Fuzzy(f => f.OnField(p => p.Name).Value(query).OnField(r => r.Category).Value(category))));
but it is not working with query field now. but it works with category now. here is what I get when I type name but dont select category:
StatusCode: OK,
Method: POST,
Url: http://server.abc.com:9200/pollit-dev/polls/_search,
Request: {
"query": {
"fuzzy": {
"category": {
"value": "Select a Category"
}
}
}
},
Response: {"took":2892,"timed_out":false,"_shards":{"total":5,"successful":5,"failed":0},"hits":{"total":0,"max_score":null,"hits":[]}}
I tried this one well:
var result = client.Search<Models.Search.Poll>(s => s.MatchAll().Query(q => q.Term(p => p.Name, query) || q.Term(p => p.Category,category) || q.Term(p => p.Location, Location)
but no luck so far.
Regards,
Asif Hameed
You have multiple options for that.
First one is almost like yours but you have to use a Bool condition there.
var result = client.Search<Models.Search.Poll>(s => s
.MatchAll()
.Query(q => q
.Bool(b => b
.Must(m => m.Term(p => p.Name, query) || m.Term(p => p.Category,category) || m.Term(p => p.Location, Location))
)
)
);
Now another option is to use queryContainers. Something like this:
var result = _Instance.Search<Models.Search.Poll>(q => q
.Query(qq =>
{
QueryContainer termQuery = null;
QueryContainer locationQuery = null;
QueryContainer categoryQuery = null;
termQuery = qq.Term(p => p.Name, query);
categoryQuery = qq.Term(p => p.Category,category);
locationQuery = qq.Term(p => p.Location, Location);
return termQuery || categoryQuery || locationQuery;
})
);
You can also elaborate the QueryContainers and add multiple search parameters there.
Hope this helps you. Great day!