I am re-writing an existing legacy system that uses stored procedures to retrieve the data needed.
The new design will have the normal column sorting and text filtering, but I came across something that has me stumped.
I am able to perform a LINQ query on the retrieved data and get my desired result as follows:
var customerIDParam = new SqlParameter("#customerID", 452);
var result =
db.Database.SqlQuery<InventoryDetail>("map_efs_InventoryDetail #customerID", customerIDParam).ToList();
// this works!
var finalResult1 = from s in result
.Where(s => s.cProductDescription.Contains("E"))
.OrderBy(s => s.cProductDescription)
select s;
return View(finalResult1.ToList());
I would really like to build the LINQ statement dynamically as follows BUT THIS FAILS, always returning the full query
var customerIDParam = new SqlParameter("#customerID", 452);
var result =
db.Database.SqlQuery<InventoryDetail>("map_efs_InventoryDetail #customerID", customerIDParam).ToList();
// This does not work ???
var finalResult2 = from s in result select s;
finalResult2.OrderBy(s => s.cProductDescription);
finalResult2.Where(s => s.cProductDescription.Contains("E"));
return View(finalResult2.ToList());
If anyone can assist I would appreciate it.
Regards
Mark
OrderBy/Where/Etc are "pure" methods, they will return an other IEnumerable, so your result never gets ordered or filtered, you need to assign the new operations (I say operations beacuse IEnumerables have deferred execution), eg:
Assigning variables:
List<Customer> customers = context.Customers.ToList();
IEnumerable<Company> companies = customers.Select(e => e.Company);
IEnumerable<Company> companiesFiltered = companies.Where(e => e.Active);
IOrderedEnumerable<Company> companiesOrdered = companiesFiltered.OrderBy(e => e.Id);
companiesFiltered = companiesOrdered.ThenBy(e => e.Code); // because the variable and result are the same type we can do this
Using returning values:
var finalResult2 = result.Select(r => r.s)
.Where(s => s.cProductDescription.Contains("E"))
.OrderBy(s => s.cProductDescription);
Because every operation returns another IEnumrable we can "chain calls" fluently like that. Remember that actual execution takes place when you call ToList().
I discovered my own error.
var finalResult2 = from s in result select s;
finalResult2 = finalResult2.OrderBy(s => s.cProductDescription);
finalResult2 = finalResult2.Where(s => s.cProductDescription.Contains("E"));
return View(finalResult2.ToList());
Related
I have two tables; Notification and SeenBy.
Notification:
Notification.Id
Notification.Timestamp
Notification.Message
SeenBy
SeenBy.Id
SeenBy.NotificationId
SeenBy.ClientId
SeenBy.Timestamp
I need to get the rows from table Notification not seen before (Count=0) using secondary table SeenBy.
What would be the Linq query or Lambda expressions?
You can try something like this:
var seenNotificationIds = seenByCollection.Select(x => x.NotificationId).Distinct();
var seenNotifications = notifications.Where(x => seenNotificationIds.Contains(x.Id));
var notSeenNotifications = notifications.Except(seenNotifications);
notSeenNotifications.Dump();
You can use this code:
var allNotificationObjects = ...; // all your notification objects
var seenByObjects = ...; // all seen by objects
var seenNotificationIds = seenByObjects
.Select(item => item.NotificationId)
.Distinct()
.ToHashSet();
var result = allNotificationObjects
.Where(item => !seenNotificationsIds.Contains(item.Id))
.ToList(); // all notifications which are not seen
Okay, so this is probably from not knowing how to use EF core correctly as this is my 2nd day using but I appear to have to run .Include() in order to query against the "inner join" this method creates.
I've got this bit working and filtering down my results, but I don't want to return the include in the model as it's making a 256kb JSON response turn into a 2.8Mb JSON response.
public IEnumerable<Property> GetFeaturedProperties()
{
var properties = _db.Properties
.Include(p => p.GeoInfo)
.Include(p => p.FeaturedUntil)
.ToArray();
var featuredProperties = new List<Property>();
var DateTimeNow = DateTime.Now;
var midnightToday = DateTimeNow.AddHours(-DateTimeNow.Hour)
.AddMinutes(-DateTimeNow.Minute)
.AddSeconds(-DateTimeNow.Second-1);
for (var i = 0; i < properties.Count(); i++)
{
var property = properties[i];
if(property.FeaturedUntil.Any(p => p.FeaturedDate >= midnightToday))
featuredProperties.Add(property);
}
return featuredProperties;
}
So the offending line is .Include(p => p.FeaturedUntil). As this is an Array of dates that can be up anything from 10-1000 rows per joined row. It includes ALL data, even historical so this is really racking up data.
Can I run my query and then run something to .RemoveInclude(p => p.FeaturedUntil)?
You don't need to load the navigation properties in order to apply filtering. When you access a navigation property inside LINQ to Entities query, it's translated to the corresponding SQL construct, including JOINs. No real object/collections are involved. The whole query (with some exceptions) executes at server (database) side.
In your case, the following simple query will do the job:
public IEnumerable<Property> GetFeaturedProperties()
{
var DateTimeNow = DateTime.Now;
var midnightToday = DateTimeNow.AddHours(-DateTimeNow.Hour)
.AddMinutes(-DateTimeNow.Minute)
.AddSeconds(-DateTimeNow.Second-1);
return _db.Properties
.Include(p => p.GeoInfo) // assuming you want to return this data
.Where(p => p.FeaturedUntil.Any(p => p.FeaturedDate >= midnightToday))
.ToList();
}
For more info, see How Queries Work documentation topic.
We have a duplicate part of our LINQ METHOD syntax query. Here is a contrived example.
IQueryable<orders> query = _context.Set<orders>();
var result = query.Select(p => new{
REMAINING = p.qtyOrdered + p.alreadysent,
AWATING = p.qtyOrdered + p.alreadysent
}).ToList();
So we are trying to resolve the duplicate part by putting something in a method and then calling that and getting some sort of result. So something like this....
private IQueryable WhatsLeft()
{
IQueryable<orders> query = _context.Set<orders>();
return query.Select(p => new{p.qtyOrdered + p.alreadysent});
}
IQueryable<orders> query = _context.Set<orders>();
var result = query.Select(p => new{
REMAINING = WhatsLeft(),
AWATING = WhatsLeft()
}).ToList();
Is this at all possible and if so can anyone give me some brief advise on how I would achieve this.
Wouldn't you just simply pass the Order object to the new function directly?
private int Total(Order order)
{
return order.qtyOrdered + order.alreadySent;
}
IQueryable<orders> query = _context.Set<orders>();
var result = query.Select(p => new{
REMAINING = Total(p),
AWATING = Total(p)
}).ToList();
If I understand what you're after correctly. I can't remember off the top of my head how well Linq to sql etc can handle functions, interpreting them into SQL functions. Maybe you could give it a try.
Alternatively, to reduce the complexity of the function (to facilitate L2S conversion) you can make the parameters granular on the function such as:
private int Total(int left, int right)
{
return left + right;
}
Then make the call more like:
var result = query.Select(p => new{
REMAINING = Total(p.qtyOrdered, p.alreadysent),
AWATING = Total(p.qtyOrdered, p.alreadysent)
}).ToList();
UPDATE:
Have you thought about querying the calculation up front?
var result = query.Select(c => c.qtyOrdered + c.alreadysent).Select(p => new {
REMAINING = p,
AWAITING = p
}).ToList();
Additional information: LINQ to Entities does not recognize the method 'System.String ToString(System.Object)' method, and this method cannot be translated into a store expression.
Ok, "ToString()" cannot be translated into a store expression, and error is clear.
This is my code:
var narudzbe = db.Narudzbe
.Where(x => x.KupacID == id && x.Status == true)
.Select(x => new NarudzbeVM()
{
BrojNarudzbe = x.BrojNarudzbe,
Datum = x.Datum,
KupacID = x.KupacID,
NarudzbaID = x.NarudzbaID,
Otkazano = x.Otkazano,
Status = x.Status,
StavkeNarudzbe = db.NarudzbaStavke
.Where(y => y.NarudzbaID == x.NarudzbaID)
.Select(z => new NarudzbaStavkeVM()
{
Kolicina = z.Kolicina,
NarudzbaID = z.NarudzbaID,
NarudzbaStavkaID = z.NarudzbaStavkaID,
Proizvod = db.Proizvodi
.Select(t => new ProizvodTest()
{
Cijena = t.Cijena,
ProizvodID = t.ProizvodID,
JedinicaMjere = t.JediniceMjere.Naziv,
Naziv = t.Naziv,
Sifra = t.Sifra,
SlikaThumb = Convert.ToString(t.SlikaThumb)
})
.Where(k => k.ProizvodID == z.ProizvodID)
.FirstOrDefault()
}).ToList()
}).ToList();
I want to convert byte[] to string, since my class accept string for attribut "SlikaThumb". So,
SlikaThumb = Convert.ToString(t.SlikaThumb)
t.SlikaThumb is type of byte[]. Is there way to do it in lambda ?
As you've said, Linq to Entities doesn't recognize .ToString() calls; it doesn't know how to convert these into SQL. However, you can run that in memory; simply resolve the objects (call .ToList() or something) and then perform the select statement on the in-memory objects. It'll be Linq to Objects and that'll be permitted.
Whether that will work for the purpose you intend is a different question but you definitely will be able to call .ToString() on any object in this way.
I guess the best thing you could do is retrieve the object from database as they are, by using ToList() or an equivalent method to actually do the query, then after that, you work on the retrieved list to convert to the objects you want to send to Android. As far as I know, there is no translated method to T-SQL from LinqToEntities to convert a binary field into a Base64 string.
Ok, this helps. As #Casey say:
Linq to Entities doesn't recognize .ToString() calls; it doesn't know how to convert these into SQL. However, you can run that in memory; simply resolve the objects (call .ToList() or something) and then perform the select statement on the in-memory objects. It'll be Linq to Objects and that'll be permitted.
I tried it on my code and it works. What i done ? I first call ToList() method whenever i getting data from database, and then perform the operations.
This code works fine...
List<NarudzbeVM> narudzbe = db.Narudzbe.Where(x => x.KupacID == id).ToList().
Select(x => new NarudzbeVM()
{
BrojNarudzbe = x.BrojNarudzbe,
Datum = x.Datum,
KupacID = x.KupacID,
NarudzbaID = x.NarudzbaID,
Otkazano = x.Otkazano,
Status = x.Status,
StavkeNarudzbe = db.NarudzbaStavke.Where(y => y.NarudzbaID == x.NarudzbaID).ToList().
Select(z => new NarudzbaStavkeVM()
{
Kolicina = z.Kolicina,
NarudzbaID = z.NarudzbaID,
NarudzbaStavkaID = z.NarudzbaStavkaID,
ProizvodID = z.ProizvodID,
Proizvod = db.Proizvodi.Where(k => k.ProizvodID == z.ProizvodID).ToList().
Select(t => new ProizvodTest()
{
Cijena = t.Cijena,
ProizvodID = t.ProizvodID,
JedinicaMjere = t.JediniceMjere.Naziv,
VrstaProizvoda = t.VrsteProizvoda.Naziv,
Naziv = t.Naziv,
Sifra = t.Sifra,
SlikaThumb = Convert.ToBase64String(t.SlikaThumb),
}).FirstOrDefault()
}).ToList()
}).ToList();
try with this
string yourString= System.Text.Encoding.Default.GetString(
System.Text.Encoding.Default.GetBytes(yorbyteArray));
I need select all elements from a set whose Id property is contained within a second set. Can "SelectMany()" be used to accomplish this? What is the most efficient / best solution for this type of matching problem.
Example:
Select all DateRangeIds for a given ReportId by way of a joining entity set.
Sets:
Reports {ReportId, ReportName}
ReportDateRanges {DateRangeId, ReportId, ReportDateRangeId}
DateRanges {DateRangeId, DateRangeName}
Here is my solution's code. I am unsure if this is the proper approach, but this does solve the problem I've described:
var report = Reports.Take(1).FirstOrDefault();
int reportId = Convert.ToInt32(report.Id);
var dateRangeIds = ReportDateRanges.Where(rdr => rdr.ReportId == reportId).OrderBy(it => it.DateRangeId).Select(it => it.DateRangeId);
var dateRanges = DateRanges.Where(dateRange => dateRangeIds.Contains(dateRange.Id));
LINQ experts, please feel free to critique this code and offer any suggestions. Thanks for the help!
Well, you can use an Enumerable.Intersect(Of TSource) Method (IEnumerable(Of TSource), IEnumerable(Of TSource), IEqualityComparer(Of TSource))
for example:
var list1 = new List<int> {1,2,3,4,5,6,7,8};
var list2 = new List<int> {9,10,11,12,13,4,5};
list1.Intersect(list2);
result
4,5
Using overload specified in link, you can specify EqualityComparer for your custom object in order to find intersection of both enumerations.
Hope this helps.
I think your code is simple and readable but there are something which is not good:
var report = Reports.Take(1).FirstOrDefault();
you can write:
var report = Reports.FirstOrDefault();
And in this line:
var dateRangeIds = ReportDateRanges.Where(rdr => rdr.ReportId == reportId)
.OrderBy(it => it.DateRangeId)
.Select(it => it.DateRangeId);
you used orderby but you don't need this.
You can join the collections.
Given that you have the reportId you can issue this query.
Reports
.Where(report => report.ReportId == reportId)
.Join(ReportDateRanges,
report => report.ReportId,
rdr => rdr.ReportId,
(report, reportDateRange) => reportDateRange)
.Join(DateRanges,
rdr => rdr.DateRangeId,
dateRange => dateRange.DateRangeId,
(reportDateRange, dateRange) => dateRange);
Here's one way to do it:
IEnumerable<SomeTypeWithAnIDProperty> sourceSequence = //whatever
IEnumerable<TypeOfTheIDProperty> ids = //whatever
var selectedItems =
from sourceObject in sourceSequence
join id in ids
on sourceObject.ID equals id
select sourceObject;
Or, to use your example
var dateRangeIds = ReportDateRanges
.Where(rdr => rdr.ReportId == reportId)
.OrderBy(it => it.DateRangeId)
.Select(it => it.DateRangeId);
var dateRanges = DateRanges.Join(dateRangeIds, dateRange => dateRange.Id, id => id, (dateRange, id) => dateRange);