I have two collections, one is a list of image names, the second is a subset of that list. When a task has been completed its name is inserted into the second collection.
I need to retrieve a set of not yet completed image names from the first collection. I have achieved this successfully with:
var processedNames = processed.AsQueryable().Select(x => x.ImageName).ToArray();
foreach (var result in results.Where(x => !processedNames.Contains(x.ImageName))
However this brings a large list of strings back from the database and then sends it back to the database in a single document, which as well as being inefficient will break eventually.
So I tried to rewrite it so it's all performed server side with:
var results = from x in captures
join complete in processed.AsQueryable() on x.ImageName equals complete.ImageName into completed
where !completed.Any()
select x;
This fails with:
System.NotSupportedException: '$project or $group does not support {document}.'
I also tried using the non LINQ API:
var xs = capturesCollection.Aggregate()
.Lookup("Processed", "ImageName", "ImageName", #as: "CompletedCaptures")
.Match(x => x["CompletedCaptures"] == null)
.ToList();
This fails with:
MongoDB.Bson.BsonSerializationException: 'C# null values of type 'BsonValue' cannot be serialized using a serializer of type 'BsonValueSerializer'.'
How can I achieve this query completely server side with the C# driver? A pure LINQ solution is preferable for portability.
I worked out how to do it with the Aggregate API:
var results = capturesCollection.Aggregate()
.As<CaptureWithCompletions>()
.Lookup(processed, x => x.ImageName, x => x.ImageName, #as:(CaptureWithCompletions x) => x.CompletedCaptures)
.Match(x => !x.CompletedCaptures.Any())
//.Limit(2)
.ToList();
I am having trouble trying to understand how to perform an order by in a LINQ to Entities call to return data organized in the desired order. The database used is postgresql. The order by in postgres is:
SELECT
*
FROM
part
ORDER BY
split_part(partnumber, '-',1)::int
, split_part(partnumber, '-',2)::int
Partnumber is a string field which is formated into 2-3 segments which are numeric separated by '-'. eg:
1-000235
10-100364
9-123456
etc.
I would want the sorted result to return:
1-000235
9-123456
10-100364
I have a test VB.Net app I am trying to figure out how to do this:
Using ctx As New EFWeb.MaverickEntities
Dim myparts = ctx.parts.
OrderBy(Function(e) e.partnumber).
ToList()
For Each pt As part In myparts
Console.WriteLine("{0} - {1}", pt.partnumber, pt.description)
Next
End Using
I tried doing: CInt(e.partnumber.Split("-")(0)) to force sorting for the first segment of the partnumber, but errored out because of the the compiler did not like the array referrence for the result of the Split() call.
If anybody knows of a good current reference for LINQ to Entities ... that would be appreciated.
You didn't share your Linq code. Anyway I would get the data to client side and then do the ordering. In C#:
var result = ctx.Parts.AsEnumerable()
.Select(p => new {p, pnSplit = p.PartNumber.Split('-')})
.OrderBy(x => int.Parse(x.pnSplit[0]))
.ThenBy(x => int.Parse(x.pnSplit[1]))
.Select(x => x.p);
In VB it should be:
Dim result = ctx.Parts.AsEnumerable()
Select(Function(p) New With {p, .pnSplit = p.PartNumber.Split("-"c)}).
OrderBy(Function(x) Integer.Parse(x.pnSplit(0))).
ThenBy(Function(x) Integer.Parse(x.pnSplit(1))).
Select(Function(x) x.p)
Note the integer.Parse. Otherwise it would be alphabetic sort.
I am getting the following error:
Only parameterless constructors and initializers are supported in LINQ
to Entities.
I am trying to query data from a result set, and part of the new result set returns a new date field.
var result = debts.Select(x => new
{
x.Snowball.User.Email,
x.SnowballID,
x.Description,
x.ID,
x.DueDayOfMonth,
Due = new DateTime(ExecutionDate.Year,
ExecutionDate.Month,
x.DueDayOfMonth)
}).ToList();
Is there a way I can create this deduced datetime?
I came here looking for the same thing, but on further research found another way using DbFunctions.CreateDateTime in System.Data.Entity. Using this method your query would look like this:
var result = debts.Select(x => new
{
x.Snowball.User.Email,
x.SnowballID,
x.Description,
x.ID,
x.DueDayOfMonth,
Due = DbFunctions.CreateDateTime(ExecutionDate.Year,
ExecutionDate.Month,
x.DueDayOfMonth, 0,0,0)
}).ToList();
EDIT: This is for EF6 and later, for earlier versions of EF use System.Data.Entity.Core.Objects.EntityFunctions instead of DbFunctions
LINQ to Entities has a boundary for the query.
The IQueryable result allows one or more filters and selections etc. to be added step by step if you wish.
While the query is being added to nothing has hit the database yet; only when you access the result set will the query be constructed by the LINQ Provider (a single Transact SQL Query for example), then run on the database, and its result returned.
In the case you have shown, you are trying to create a new object (Date - but could also be one of your own classes) in the database's result set.
So, for each row returned from the database query you are trying to create a column from an object (from your code base) different for each row (need to pass the parameters to the constructor).
Because the underlying provider cannot guarantee to be able to create arbitrary objects from an external source on the fly, this is not allowed (prevented by the LINQ Provider).
The query that will be run against the database is 'debts'. This will return all of the rows from the query unfiltered (as there is no WHERE clause).
The next query will be run in your code. In your code you can use parameterised constructors - and is now LINQ To Objects.
So the way to distinguish the separate stages of the query, and do what you want to do, is to place the ToList() at the end of the query that runs against the database so that the query is generated, run, and the results returned.
Then construct and run your next query (in your code) on those results.
var result = debts.ToList().Select(x => new
{
x.Snowball.User.Email,
x.SnowballID,
x.Description,
x.ID,
x.DueDayOfMonth,
Due = new DateTime(ExecutionDate.Year, ExecutionDate.Month, x.DueDayOfMonth)
});
You could create your own Date class with a parameter-less constructor and set it using property initializer syntax like
Due = new Date(){Year = ExecutionDate.Year, Month = ExecutionDate.Month, Day = x.DueDayOfMonth}
Then just define a cast from Date to DateTime.
You may try this:
var result = debts.Select(x =>
new
{
x.Snowball.User.Email, x.SnowballID, x.Description, x.ID,
x.DueDayOfMonth,
exY = ExecutionDate.Year,
exM = ExecutionDate.Month,
exD = x.DueDayOfMonth)
}).ToList()
.Select(a => new {Email, SnowballID, Description, ID, Due=new DateTime(exY, exM, exD)})
.ToList()
I have tried to find an answer for this.
I am using LINQ and trying to filter a database list with another list, to remove countries from a list of countries where a member is already a citizen.
var currentCitizenships = DbContext.Citizenships
.Where(c => c.MemberId == CurrentUser.MemberId)
.Include(c => c.Country)
.ToList();
var filtered = DbContext.Countries
.Where(c => !currentCitizenships.Any(current => current.Country.CountryId == c.CountryId));
I am getting a Not supported exception with the following message:
Unable to create a constant value of type 'Project.EntityFramework.Models.Citizenship'. Only primitive types or enumeration types are supported in this context.
Two Solutions Worked
Remove the ToList() of the first query.
The selected answer.
I've picked 1. due to using less lines and was a simpler solution with the same result.
It seems that it cannot create a valid SQL query using whatever is stored in currentCitizenships.
Get the list of country id's you need first, and then modify your query to use Contains on the simple collection of integers (or whatever CountryId is) instead.
var countryIds = currentCitizenships.Select(x => x.Country.CountryId).ToList();
var filtered = DbContext.Countries.Where(c => !countryIds.Contains(c.CountryId));
On the query below how can remove de time part of the datetime column to get only the distinct dates?
using (var ctx = new DBConn())
{
var q = ctx.Table.Select(r => r.datetimefield).Distinct();
}
You are stumbling over a fault with linq-to-sql or EF (I don't know which one you are using). The straight forward solution would be to use the DateTime.Date property, however, this is unsupported in both ORMs, it doesn't map to an SQL method.
You have two solutions:
eager evaluation of the query by using ToList:
var q = ctx.Table.ToList().Select(r => r.datetimefield.Date).Distinct();
create a field detailing only the date component in the database. This is the way I usually go as you can stay in the database and execute the query there.
Assuming r.datetimefield is a DateTime, you can use DateTime.Date to remove the time component:
var q = ctx.Table.Select(r => r.datetimefield.Date).Distinct();