Multiple database row deletes in a single ActionResult? (ASP.NET) [duplicate] - c#

I'm currently using a single query in two places to get a row from a database.
BlogPost post = (from p in dc.BlogPosts
where p.BlogPostID == ID
select p).Single();
The query is fine when retrieving the row to put data in to the text boxes, but it returns an error "Sequence contains no elements" when used to retrieve the row in order to edit it and put it back in to the database. I can't understand why it might find an appropriate row in one instance but not another.
(Using ASP.NET MVC and LINQ)

From "Fixing LINQ Error: Sequence contains no elements":
When you get the LINQ error "Sequence contains no elements", this is usually because you are using the First() or Single() command rather than FirstOrDefault() and SingleOrDefault().
This can also be caused by the following commands:
FirstAsync()
SingleAsync()
Last()
LastAsync()
Max()
Min()
Average()
Aggregate()

Please use
.FirstOrDefault()
because if in the first row of the result there is no info this instruction goes to the default info.

Well, what is ID here? In particular, is it a local variable? There are some scope / capture issues, which mean that it may be desirable to use a second variable copy, just for the query:
var id = ID;
BlogPost post = (from p in dc.BlogPosts
where p.BlogPostID == id
select p).Single();
Also; if this is LINQ-to-SQL, then in the current version you get a slightly better behaviour if you use the form:
var id = ID;
BlogPost post = dc.BlogPosts.Single(p => p.BlogPostID == id);

In addition to everything else that has been said, you can call DefaultIfEmpty() before you call Single(). This will ensure that your sequence contains something and thereby averts the InvalidOperationException "Sequence contains no elements". For example:
BlogPost post = (from p in dc.BlogPosts
where p.BlogPostID == ID
select p).DefaultIfEmpty().Single();

This will solve the problem,
var blogPosts = (from p in dc.BlogPosts
where p.BlogPostID == ID
select p);
if(blogPosts.Any())
{
var post = blogPosts.Single();
}

I had a similar situation on a function that calculates the average.
Example:
ws.Cells[lastRow, startingmonths].Value = lstMediaValues.Average();
Case Solved:
ws.Cells[lastRow, startingmonths].Value = lstMediaValues.Count == 0 ? 0 : lstMediaValues.Average();

Reason for error:
The query from p in dc.BlogPosts where p.BlogPostID == ID select p returns a sequence.
Single() tries to retrieve an element from the sequence returned in step1.
As per the exception - The sequence returned in step1 contains no elements.
Single() tries to retrieve an element from the sequence returned in step1 which contains no elements.
Since Single() is not able to fetch a single element from the sequence returned in step1, it throws an error.
Fix:
Make sure the query (from p in dc.BlogPosts where p.BlogPostID == ID select p)
returns a sequence with at least one element.

Related

Why do these two linq queries return different numbers of results?

In a web application that I work with I found a slow piece of code that I wanted to speed up a bit. Original code below:
foreach (Guid g in SecondaryCustomersIds)
{
var Customer = (from d in Db.CustomerRelationships
join c in Db.Customers on
d.PrimaryCustomerId equals c.CustomerId
where c.IsPrimary == true && d.SecondaryCustomerId == g
select c).Distinct().SingleOrDefault();
//Add this customer to a List<>
}
I thought it might be faster to load this all into a single query, so I attempted to rewrite it as the query below:
var Customers = (from d in Db.CustomerRelationships
join c in Db.Customers on
d.PrimaryCustomerId equals c.CustomerId
where c.IsPrimary == true && SecondaryCustomersIds.Contains(d.SecondaryCustomerId)
select c).Distinct();
Which is indeed faster, but now the new query returns fewer records than the first. It seems to me that these two chunks of code are doing the same thing and should return the same number of records. Can anyone see why they would not? What am I missing here?
It's possible for the first query to add a null object to the list (SingleOrDefault will return the default for the type, or null in this case, if it can't find a matching entity). Thus, for every Customer without a matching relationship, you could be adding a null object to that List<>, which would increase the count.
In your first scenario, does your final List<Customers> have duplicates?
You're calling Distinct, but also looping, which means you're not doing Distinct on your entire collection.
Your second example is calling Distinct on the entire collection.

insert from linq to sql with join

I have the following query
var listOfFollowers = (from a in db.UserLinks
where a.TargetUserID == TargetUserID && a.LinkStatusTypeID == 2
join b in db.UserNotifications on (int)a.OriginUserID equals b.TargetUserID
select b);
then I want to update once column on each row ( or object) returned
foreach (var a in listOfFollowers)
{
a.UserNotifications += HappeningID.ToString() + "|";
}
db.SubmitChanges();
The query seems to work , and when I put the generated SQL into SSMS it works fine , but when I run the entire code I get exception for trying to cast to int, don't make too much sense.
Is this ok , to do a query using a join , but only returning one table , change one property, then submitchanges?
The reason you are getting can't cast exception is that in the LINQ statement it is invalid to do cast. Other things which we can't do is to use regular method calls such as toString()
(int)a.OriginUserID is not allowed in
var listOfFollowers = (from a in db.UserLinks
where a.TargetUserID == TargetUserID && a.LinkStatusTypeID == 2
join b in db.UserNotifications on (int)a.OriginUserID equals b.TargetUserID
select b);
This problem will occur because parser tries to convert it into a equivalent SQL but doesn't find any equivalent. Other such cases are when you try to invoke toString(). Several Good responses here:
linq-to-entities-does-not-recognize-the-method
For your current scenario, I believe you have to
1. get the results from first query
2. cast the value
3. Make the second LINQ query
Hope this helps!
Most likely, problem occures in this piece of code (int)a.OriginUserID.
Try remove casting or use SqlFunctions.StringConvert() to compare strings.

Request only first item Entity Framework

I'm looking for the most efficiant method to call the first and only the first item from a SQL Server database using Entityframework and linq.
I'm currently using
public static UserProfile GetUserProfile(Guid userID)
{
UserProfile oProfile = null;
using (var context = new MyEntities())
{
var profiles = from c in context.UserProfiles where c.UserID == userID select c;
if(profiles.Any())
{
oProfile = profiles.First();
}
}
return oProfile;
}
This however from what I can tell takes two DB ops to complete, one to check if the record exists and a second to return it. I'm sure there has to be a better pattern / method and I'm just not seeing it.
It's very simple: Use FirstOrDefault().
When there is no entry it will return null (like you have already), else it'll return the first entry. If you don't want your variable to take the null value, use a substitute in between.
edit:
Your code could be equally replaced with the following code, just that this one will just query once against the database.
public static UserProfile GetUserProfile(Guid userID)
{
UserProfile oProfile = null;
using (var context = new MyEntities())
{
oProfile = (from c in context.UserProfiles where c.UserID == userID select c).FirstOrDefault();
}
return oProfile;
}
If only one item should exist (as it looks in this case) then you should consider using Single(). Single will return the first item but throw an exception if more than one item exists - this can help maintain data quality if only a single item should exist.
If only one item should exist but it is optional then use SingleOrDefault which will act as Single but return null if no item exists.
You need to use First() or FirstOrDefault() without calling .Any()
var profile = (from c in context.UserProfiles where c.UserID == userID select c).First();
First() throws an exception if no records returned but FirstOrDefault() returns null in that case
Both will generate SQL like this:
SELECT TOP (1) ...
FROM ...
You should use the Take method:
Entity Framework/Linq to SQL: Skip & Take
It will only require one hit to the database.

Cannot implicitly convert type 'System.Linq.IQueryable<int>' to 'int?'

var cityList = from country in
doc.Element("result")
.Element("cities")
.Descendants("city")
select new {
Name = country.Element("name").Value,
Code = country.Element("code").Value,
CountryCode = int.Parse(country
.Element("countrycode")
.Value)
};
foreach(var citee in cityList)
{
City city = new City();
city.CountryID = from cnt in db.Countries
where cnt.DOTWInternalID == citee.CountryCode
select cnt.ID;
}
I'm getting an error on the second query as seen in the title of this post. I tried converting to int to nullable int but nothing worked. Help me, guys.
Thanks
it will return an iQueryable, you will need to do something like using the First
cit.CountryID = db.Countries.First(a=>a.DOTWInternalID == citee.CountryCode).ID
It has elapsed a long time since the last update to the post but i think it's worth improving the solution.
In my opinion the solutions posted for this particular scenario are not the best way in terms of performace to get the ID you need. A better solution is as follows.
db.Countries.Where(a=>a.DOTWInternalID == citee.CountryCode)
.Select(a => a.ID).FirstOrDefault();
The previous statemants basically runs a SQL query similar to the following one:
SELECT TOP (1) ID
FROM [dbo].[Countries]
WHERE DOTWInternalID = 123
The proposed solutions work but basically do a "SELECT *" to create the entity with all the values and then obtain the ID from the object just created.
You can use Linqpad to actually see the generated SQL and tune up LINQ queries or Lambdas.
Hope it helps to some others that get to this post.
Here is the problem and solution
from cnt in db.Countries where cnt.DOTWInternalID == citee.CountryCode select cnt.ID part. If you omit the ID then it returns a Generic IEnumerable with Country(hoping that you have Country class). So what you have to do is first return the select criteria and select the first row then the ID field. Same like shown below.
cit.CountryID = (from cnt in db.Countries where cnt.DOTWInternalID == citee.CountryCode select cnt).First<Country>().ID;
This will solve your problem.
IQueryable is not a single int - but a query that can represent a collection.
As the error message says, your Linq query returns an System.Linq.IQueryable (for all intents and purposes a collection of ints). If you'd like to get one of them, you can either call First or ElementAt(n) to get the n'th element.
cit.CountryID = db.Countries.First(a=>a.DOTWInternalID == citee.CountryCode).ID

How can I combine these linq queries into one?

Being new to LINQ, I created a couple queries and would like to combine them into one, but I am not sure how to do it. Here they are:
var u = dc.Users.Where(w => w.UserName == userName).SingleOrDefault();
var m = dc.Memberships.Where(w => w.UserId == u.UserId).SingleOrDefault();
m.PasswordQuestion = securityQuestion;
m.PasswordAnswer = securityAnswer;
dc.SubmitChanges();
dc.Users is the aspnet_Users table
dc.Membership is the aspnet_Membership table
Also, What is the difference between SingleOrDefault and FirstOrDefault?
Not sure if they have a relationship (they should). If they do, then the linq-to-sql designer will give you a User property on the membership object (or the other way around). Then you can write something like this:
var membership = dc.Memberships.Where(x => x.User.UserName == userName).SingleOrDefault();
If they don't have a relationship you can write something like this:
var membership = (from m in dc.Membership join u in dc.Users on u.UserId equals m.UserId
where u.UserName == userName
select u).SingleOrDefault();
The difference between SingleOrDefault() and FirstOrDefault() is that SingleOrDefault() assumes that there is no more then one item that matches the query. If two items match the query then a exception will be thrown. While if you use FirstOrDefault() and there is two items that match the query then the first one will be selected.
SingleOrDefault means "if there are no elements, give me the default, if there is one, give me it, otherwise, throw an exception". FirstOrDefault means "if there are no elements then give me the default, otherwise give me the first one".
As for your question about combining the queries -- why would you? If the code is working well as written, why change it?
To answer a question you didn't ask: the usual way of combining queries is to use a query continuation. A common pattern is:
var q1 = from y in something
somequeryclauses;
var q2 = from x in q1
someotherquerqyclauses;
You could write this as one big query like this:
var q2 = from x in (from y in something
somequeryclauses)
someotherqueryclauses;
which gets hard to read. You can combine the two queries with a query continuation:
var q2 = from y in something
somequeryclauses
into x
someotherqueryclauses;
Make sense?
SingleOrDefault will throw an error if your sequence contains more than one element, FirstOrDefault does not. In this case, you'd probably want FirstOrDefault, because users can have more than one membership.
var m = dc.MemberShips where(w => w.UserId.UserName == userName).FirstOrDefault();
I don't have Visual Studio in front of me, but it would be something like this:
var m = dc.Memberships.Where(w => w.Users.UserName == userName).SingleOrDefault();
m.PasswordQuestion = securityQuestion;
m.PasswordAnswer = securityAnswer;
dc.SubmitChanges();
w.Users allows you to follow the foreign key link between the membership and users tables.
SingleOrDefault will throw an exception if more than one result is returned. FirstOrDefault returns the first record only.

Categories

Resources