Linq Get Latest Date Query - asp.net-mvc

I am trying to get the latest date based on my controller below but I was hit with this error :
"Unable to cast object of type 'System.Data.Entity.Infrastructure.DbQuery1[<>f__AnonymousType201[System.Nullable`1[System.DateTime]]]' to type 'System.IConvertible'."
var latestDt = from n in db.Books
where n.id == id
select new { Date = n.dtBookBorrowed};
DateTime dtPlus1Year = Convert.ToDateTime(latestDt);
May I know how do I get just the column latestDate in linq?

You can try this to get list of date order by latest insert to db.
var latestDt = db.Books.Where(n => n.id == id).OrderByDescending(x => x.dtBookBorrowed).Select(x => x.dtBookBorrowed).ToList();

I think if you use
DateTime.Parse(item.dateAsString)
your problem should be solved.

The LINQ query expression you've defined returns a collection of anonymous object with property Date despite there might be only one record match as ID was meant to be unique.
In your case we only need the target field that can be parsed as DateTime and therefore an alternative in fluent syntax would be as following:-
var book = db.Books.SingleOrDefault(book => book.id == id); // gets matching book otherwise null
if (book != null)
{
var borrowedDate = Convert.ToDateTime(book.dtBookBorrowed);
}
Otherwise if you would like to understand more about the behaviour with query syntax which may return multiple results, you may simplify as following which returns collection of DateTime object (i.e. IEnumerable) instead:-
IEnumerable<DateTime> borrowedDates =
from n in db.Books
where n.id == id
select Convert.ToDateTime(n.dtBookBorrowed);

Related

'System.Data.Entity.Core.EntityCommandExecutionException' occurred in EntityFramework.SqlServer.dll but was not handled in user code

I did raw SQL query below to select only certain fields from a table.
{
List<CustEmpVM> CustomerVMlist = new List<CustEmpVM>();
var cid = db.Customers.SqlQuery("select SchedDate from Customer where CustID = '#id'").ToList<Customer>();
}
But i keep getting the error of:
System.Data.Entity.Core.EntityCommandExecutionException occurred in EntityFramework.SqlServer.dll but was not handled in user code
Additional information: The data reader is incompatible with the specified ALFHomeMovers.Customer. A member of the type, CustID, does not have a corresponding column in the data reader with the same name.
The exception message is pretty straightforward: the query expected to return full entity of Customer table but only SchedDate column returned, hence EF cannot done mapping other omitted columns including CustID.
Assuming Customers is a DbSet<Customer>, try return all fields from Customer instead:
// don't forget to include SqlParameter
var cid = db.Customers.SqlQuery("SELECT * FROM Customer WHERE CustID = #id",
new SqlParameter("id", "[customer_id]")).ToList();
If you want just returning SchedDate column, materialize query results and use Select afterwards:
var cid = db.Customers.SqlQuery("SELECT * FROM Customer WHERE CustID = #id",
new SqlParameter("id", "[customer_id]"))
.AsEnumerable().Select(x => x.SchedDate).ToList();
NB: I think you can construct LINQ based from the SELECT query above:
var cid = (from c in db.Customers
where c.CustID == "[customer_id]"
select c.SchedDate).ToList();
Similar issue:
The data reader is incompatible with the specified Entity Framework
Use below query instead of raw query:
{
List<CustEmpVM> CustomerVMlist = new List<CustEmpVM>();
var cid = db.Customers.Where(w=>w.Id == YOURCUSTOMERID).Select(s=>new Customer{SchedDate = s.SchedDate }).ToList();
}
It will give compile time error rather than run time error.

LINQ query with omitted user input

so I have a form with several fields which are criteria for searching in a database.
I want to formulate a query using LINQ like so:
var Coll = (from obj in table where value1 = criteria1 && value2 = criteria2...)
and so on.
My problem is, I don't want to write it using If statements to check if every field has been filled in, nor do I want to make separate methods for the various search cases (criteria 1 and criteria 5 input; criteria 2 and criteria 3 input ... etc.)
So my question is: How can I achieve this without writing an excessive amount of code? If I just write in the query with comparison, will it screw up the return values if the user inputs only SOME values?
Thanks for your help.
Yes, it will screw up.
I would go with the ifs, I don't see what's wrong with them:
var query = table;
if(criteria1 != null)
query = query.Where(x => x.Value1 == criteria1);
if(criteria2 != null)
query = query.Where(x => x.Value2 == criteria2);
If you have a lot of criteria you could use expressions, a dictionary and a loop to cut down on the repetitive code.
In an ASP.NET MVC app, chances are your user input is coming from a form which is being POSTed to your server. In that case, you can make use of strongly-typed views, using a viewmodel with [Required] on the criteria that MUST be provided. Then you wrap your method in if (ModelState.IsValid) { ... } and you've excluded all the cases where the user hasn't given you something they need.
Beyond that, if you can collect your criteria into a list, you can filter it. So, you could do something like this:
filterBy = userValues.Where(v => v != null);
var Coll = (from obj in table where filterBy.Contains(value1) select obj);
You can make this more complex by having a Dictionary (or Lookup for non-unique keys) that contains a user-entered value along with some label (an enum, perhaps) that tells you which field they're filtering by, and then you can group them by that label to separate out the filters for each field, and then filter as above. You could even have a custom SearchFilter object that contains other info, so you can have filters with AND, NOT and OR conditions...
Failing that, you can remember that until you trigger evaluation of an IQueryable, it doesn't hit the database, so you can just do this:
var Coll = (from obj in table where value1 == requiredCriteria select obj);
if(criteria1 != null)
{
query = query.Where(x => x.Value1 == criteria1);
}
//etc...
if(criteria5 != null)
{
query = query.Where(x => x.Value5 == criteria5);
}
return query.ToList();
That first line applies any criteria that MUST be there; if there aren't any mandatory ones then it could just be var Coll = table;.
That will add any criteria that are provided will be applied, any that aren't will be ignored, you catch all the possible combinations, and only one query is made at the end when you .ToList() it.
As I understand of your question you want to centralize multiple if for the sake of readability; if I were right the following would be one of some possible solutions
Func<object, object, bool> CheckValueWithAnd = (x, y) => x == null ? true : x==y;
var query = from obj in table
where CheckValue(obj.value1, criteria1) &&
CheckValue(obj.value2, criteria2) &&
...
select obj;
It ls flexible because in different situations or scenarios you can change the function in the way that fulfill your expectation and you do not need to have multiple if.
If you want to use OR operand in your expression you need to have second function
Func<object, object, bool> CheckValueWithOr = (x, y) => x == null ? false : x==y;

Cannot convert anonymous type to int - compoiled linq to sql query

I'm trying to do a compiled query but I just want it to return an int
public Func<DataContext, DateTime, int>
GetNextTourNo = CompiledQuery.Compile((DataContext db, DateTime day) => ((from b in db.GetTable<BookingType>()
where b.RecordType == "H" && b.TourStartDateTime.Value.Date == day.Date
orderby b.TourID descending
select new { nextID = b.TourID +1 }).Single()));
You could just return nextID property from selected single anonymous object
select new { nextID = b.TourID +1 }).Single().nextID
Can you provide a bit more information on the anonymous type and the context of the compiled query?
Also if you are using the query directly in linq to Entity the date comparison will not work. Entity Functions need to be used for this. This could cause the invalid return.

Getting a list of distinct entities projected into a new type with extra field for the count

I'm designing an interface where the user can join a publicaiton to a keyword, and when they do, I want to suggest other keywords that commonly occur in tandem with the selected keyword. The trick is getting the frequency of correlation alongside the properties of the suggested keywords.
The Keyword type (EF) has these fields:
int Id
string Text
string UrlString
...and a many-to-many relation to a Publications entity-set.
I'm almost there. With :
var overlappedKeywords =
selectedKeyword.Publications.SelectMany(p => p.Keywords).ToList();
Here I get something very useful: a flattened list of keywords, each duplicated in the list however many times it appears in tandem with selectedKeyword.
The remaining Challenge:
So I want to get a count of the number of times each keyword appears in this list, and project the distinct keyword entities onto a new type, called KeywordCounts, having the same fields as Keyword but with one extra field: int PublicationsCount, into which I will populate the count of each Keyword within overlappedKeywords. How can I do this??
So far I've tried 2 approaches:
var keywordCounts = overlappingKeywords
.Select(oc => new KeywordCount
{
KeywordId = oc.Id,
Text = oc.Text,
UrlString = oc.UrlString,
PublicationsCount = overlappingKeywords.Count(ok2 => ok2.Id == oc.Id)
})
.Distinct();
...PublicationsCount is getting populated correctly, but Distinct isn't working here. (must I create an EqualityComarer for this? Why doesn't the default EqualityComarer work?)
var keywordCounts = overlappingKeywords
.GroupBy(o => o.Id)
.Select(c => new KeywordCount
{
Id = ???
Text = ???
UrlString = ???
PublicationsCount = ???
})
I'm not very clear on GroupBy. I don't seem to have any access to 'o' in the Select, and c isn't comping up with any properties of Keyword
UPDATE
My first approach would work with a simple EqualityComparer passed into .Distinct() :
class KeywordEqualityComparer : IEqualityComparer<KeywordCount>
{
public bool Equals(KeywordCount k1, KeywordCount k2)
{
return k1.KeywordId== k2.KeywordId;
}
public int GetHashCode(KeywordCount k)
{
return k.KeywordId.GetHashCode();
}
}
...but Slauma's answer is preferable (and accepted) because it does not require this. I'm still stumped as to what the default EqualityComparer would be for an EF entity instance -- wouldn't it just compare based on primary ids, as I did above here?
You second try is the better approach. I think the complete code would be:
var keywordCounts = overlappingKeywords
.GroupBy(o => o.Id)
.Select(c => new KeywordCount
{
Id = c.Key,
Text = c.Select(x => x.Text).FirstOrDefault(),
UrlString = c.Select(x => x.UrlString).FirstOrDefault(),
PublicationsCount = c.Count()
})
.ToList();
This is LINQ to Objects, I guess, because there doesn't seem to be a EF context involved but an object overlappingKeywords, so the grouping happens in memory, not in the database.

How to specify a condition in an Entity Framework join?

I have a Blogs table related to BlogComments table with a FK.
I need to get, through Linq, all the BlogComments items that match a certain flag
If i do:
db.Blogs.Where(b => b.BlogComments.Where(bc=>bc.Where(bc.Flag1==true));
I get "Cannot implicity convert type IEnumerable to bool"
Which is the best way to solve this problem?
Because this expression:
b.BlogComments.Where(...)
returns an IEnumerable (of BlogComments), but you are then passing it into this method:
db.Blogs.Where(...)
which expects a function that returns a bool, not an IEnumerable.
You probably need something like this:
var blogId = 5;
db.BlogComments.Where(bc => bc.BlogId == blogId && bc.Flag1 == true)
If you need to select comments from multiple blogs, then you could try using Contains:
var blogIds = new [] {1,2,3,4,5};
db.BlogComments.Where(bc => blogIds.Contains(bc.BlogId) && bc.Flag1 == true)
If you want to place criteria on the set of blogs, as well as the comments, then you could do this in one query using a join:
var query = from b in db.Blogs
join c in db.BlogComments on c.Blog equals b
where b.SomeField == "some value"
&& c.Flag1 == true
select c;
You could write it in LINQ form.
var blogs = from b in db.Blogs
join c in db.BlogComments
on b.BlogId equals c.BlogId
where c.Flag1
select b;
If you have a composite key you can write
on new { A = b.BlogKey1, B = b.BlogKey2 }
equals new { A = c.CommentKey1, B = c.CommentKey2 }
If it were me, I would just have another DbSet in your DbContext.
DbSet<BlogComment> BlogComments
and just search through there without going through Blogs.
db.BlogComments.Where(bc => bc.Flag1 == true);
If anyone knows if there's anything wrong in doing so, then I'm all ears :)

Resources