Why does Select return a boolean? - c#

I'm working with Entity Framework 6 in MVC 5.
I have the following method:
[HttpPost]
public ActionResult UpdateDetails(ApplicationUser applicationUser)
{
var context = new ApplicationDbContext();
var user = context.Users.Select(x => x.UserName == applicationUser.UserName).FirstOrDefault();
//etc etc
}
Users is an IDbSet<ApplicationUser>.
Why am I getting a bool back from the Select method?
My expectation would be to get an ApplicationUser object back. Why isn't this the case?
Thanks

Select() projects an element of a sequence. Since x.UserName == applicationUser.UserName returns a bool, the result of the method will be a boolean.
What you want requires the Where method. This filters the sequence based on the specified predicate:
var user = context.Users.Where(x => x.UserName == applicationUser.UserName).FirstOrDefault();
Which can be shortened to:
var user = context.Users.FirstOrDefault(x => x.UserName == applicationUser.UserName);
This is possible, since this overload of FirstOrDefault() takes a filter predicate as second parameter.

Your select is returning an object that is the result of the comparison.
Change to:
var user = context.Users.FirstOrDefault(x => x.UserName == applicationUser.UserName);

It is because you are SELECTing a boolean.
Since there is no requirement specified, I am guessing your requirement from your attempted code.
use the below line.
var user=context.Users.Where(user=>user.UserName==applicationUser.UserName).FirstOrDefault();

Select literally selects something inside the arguments. So, if you have an expression that returns a bool, Select will return bool.

Related

LINQ to Entities does not recognize the method IsUserInCc

My Code:
elections = elections.Where(e => e.Creator == Username || e.Approver == Username || IsUserInCc(e.Cc,Username))
.OrderBy(e => e.Status)
.ThenByDescending(e => e.Group);
var test = elections.FirstOrDefault();
private bool IsUserInCc(string cc, string username)
{
var ccList = cc.Split(';');
if (ccList.Contains(username))
return true;
return LDAPUtility.Instance.IsUserInGroup(ccList.ToList(), username);
}
Error:
LINQ to Entities does not recognize method IsUserInCc.
From many posts, I can understand why error was thrown. Basically IsUserInCc is not available in SQL execution. I need somehow convert it back to C# to handle it.
LINQ to Entities does not recognize my method
LINQ to Entities does not recognize the method in query
LINQ to Entities does not recognize the method 'System.String ToString(Int32)'
However, in my specific case, what is the best approach?
You need to convert to list first. Also note that elections must be able to hold a list for this to run.
elections = elections.ToList().Where(e => e.Creator == Username || e.Approver == Username || IsUserInCc(e.Cc,Username))
.OrderBy(e => e.Status)
.ThenByDescending(e => e.Group);
For your function written in code, you cannot use that on Queryables. You need to convert to in-memory list and then apply the filter required using your function.
The root cause of your issue is that your underlying data isn't normalised properly. You need to put your CC's in a collection, not have them as a single deliniated string.
In SQL you'd need to add a new table called CC or something and put each user name in there and link it back to an election. Or if it's an in-memory collection, add a new property that in its Getter will do the split for you.
Either way, then you won't run into this kind of problem. If your data isn't properly structured, you will create problems for yourself further up the stack.
When you want to send request to databaseusing Linq like:
var query = listData.Where(x=>x.Id == 123);
Type of this query is IQueryable that means your query not Executed yet!
Now you are sending data as IQueryable to method and can not process on your data, you have to Execute that with methods like: Tolist(), ToListAsync() or something like these.
The best way for these is that you get data from database without that method, after that you execute your query, you can Run this method.
GoodLuck.
Can you try like this :
elections = elections.Where(e => e.Creator == Username || e.Approver == Username).Tolist().Where(e => IsUserInCc(e.Cc,Username))
.OrderBy(e => e.Status)
.ThenByDescending(e => e.Group);
var test = elections.FirstOrDefault();
private bool IsUserInCc(string cc, string username)
{
var ccList = cc.Split(';');
if (ccList.Contains(username))
return true;
return LDAPUtility.Instance.IsUserInGroup(ccList.ToList(), username);
}

Determine if record exists where two fields must match in MVC

I have a table (and a corresponding class) for this solution that has only two fields a UserId and a TicketId. Now I need to test if a record exists in this table where the UserId matches the logged in individual and TicketId matches the passed value. This is the code I tried:
bool subscriptionExists = db.TicketSubscriptions.Any(ts => ts.TicketId.Equals(db.Tickets.FirstOrDefault(t => t.TicketNumber == ticketNumber).TicketId))
.Where(ts => ts.UserId == db.Users.FirstOrDefault(u => u.NTUserName.Equals(User.Identity.Name)).UserId);
However, I am getting the following error:
'bool' does not contain an extension method for 'where' and no
extension method 'where' accepting a first argument of type 'bool'
could be found (are you missing a using directive or an assembly
reference?
Am I on the right track? or is there a much better way to test this?
You are using Where on a bool value instead of a List. Any() returns bool. You can try like following. Hope this will help you.
var ticketId=db.Tickets.FirstOrDefault(t =>t.TicketNumber==ticketNumber).TicketId;
var userId=db.Users.FirstOrDefault(u=>u.NTUserName.Equals(User.Identity.Name)).UserId;
bool subscriptionExists = db.TicketSubscriptions.
Any(ts => ts.TicketId.Equals(ticketId) && ts.UserId == userId);
You're calling the .Where on the result of the .Any, which is a boolean value. Try combining your clauses and then calling .Any on the whole thing:
bool subscriptionExists = db.TicketSubscriptions.Any(
ts => ts.TicketId.Equals(db.Tickets.FirstOrDefault(t => t.TicketNumber == ticketNumber).TicketId) &&
ts.UserId == db.Users.FirstOrDefault(u => u.NTUserName.Equals(User.Identity.Name)).UserId);
TicketSubscriptions.Any() returns a Bool.
It is result is a True or False. So you cannot continue to query with a where. Write the code more readable. You can see mistakes easier. In any() function you need a boolean statement like if statements. You can use || or && signs simply.
var userId = User.Identity.Name;
var passedValue = ... // I dont know if it is from a parameter.
bool subscriptionExists = TicketSubscriptions.Any(ts => ts.NTUserName == userId && ts.TicketId == passedValue );
your problem is that Any() returns a bool, so you can't call Where() on it.
Where, returns another IEnumerable, so if you put Where before Any(), you won't have that problem.
You can also put both conditions inside the Any() I.E. someEnumerable.Any(/*condition1*/ && /*condition1*/);
on another note, I'd make use of Navigation Properties if I were you. You can google search for "navigation properties" and the name of whatever database framework you're using(like entity framework or linq to sql) to find more information.
That will let you do things like
subscriptionExists = db.TicketSubscriptions
.Any(ts => ts.Ticket.TicketNumber == ticketNumber
&& ts.User.NTUserName == User.Identity.Name);
on yet another note, I believe that User.Identity is going to have the user id, so you don't even have to bother accessing the users table like that. Intellisence can help you find out how to access that.
Complementing the #Azim answer
When you use .FirstOrDefault must verify returned values. Otherwise if you have sure that the return value never is null must use .First
var ticketId=db.Tickets.FirstOrDefault(t =>t.TicketNumber==ticketNumber).TicketId;
varuserId=db.Users.FirstOrDefault(u=>u.NTUserName.Equals(User.Identity.Name)).UserId;
if(ticketId != null && userId != null)
{
bool subscriptionExists = db.TicketSubscriptions.
Any(ts => ts.TicketId.Equals(ticketId) && ts.UserId == userId)
}

Get ICollection property of generic type

I'm new in ASP.NET MVC 5, I need get the Icollection property and search into other property, if printed the result of the first search is fine, but when i go to search in the result is null.
what is the problem?
var userId = User.Identity.GetUserId();
var user = db.Users.Include( u=> u.Sucursales)
.Where(u => u.Id == userId)
.SingleOrDefault();
if( user != null )
{
var sucursal = user.Sucursales.Include(s => s.Emisor)
.Where(s => s.ID == suc)
.SingleOrDefault();
if (sucursal != null)
{
var tipoCfe = sucursal.Emisor.TiposCfe
.Where(t => t.ID == factura)
.SingleOrDefault();
Your query will take place right away since you are using SingleOrDefault(), see this StackOverflow question pertaining to SingleOrDefault() Your Include(s => s.Emisor) sticks out to me though. Since Emisor wasn't included when fetching the user, you will not be able to request that since your query is no longer of type IQueryable. Your query has already been executed.
In order to retrieve the data you require, you will have to obtain the data during your first query. I would do something similar to: db.Users.Include("Sucursales.Emisor") when you retrieve the user.
More on include method... MSDN Explanation of Include Method
I changed
var user = db.Users.Include( u=> u.Sucursales)
for
var user = db.Users.Include("Sucursales.Emisor")

Where clause with Linq in C# MVC 4

I'm trying to select a field that is from my UserProfile table, RoleID. The parameter passed into this Post method is Username and it is a string from a textbox which is working correctly.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult GetRoles(string UserName)
{
if (!string.IsNullOrWhiteSpace(UserName))
{
string applyfor = db.Profiles
.Select(s => s.RoleID)
.Where(a=>Profile.UserName.Contains(UserName))
.First();
ViewBag.ApplyingFor = applyfor;
However this gives me Sequence contains no elements.
I've tried several other methods, such as .Equals(). I'm pretty sure it is my where clause.
What am I doing wrong here?
Note: RoleID is not part of the Websecurity, also there is data in the database.
If you break down your code and highlight what each Lambda statement returns you'd see the issue:
string applyfor = db.Profiles
^^^^^^^^
This most likely returns something like DbSet<Profile>.
.Select(s => s.RoleID)
^^^^^^
This most likely returns IQueryable<int>. At this point you've lost the context of the profile and now only have zero or more RoleIDs.
So your a in the where statement is an int Value, you have no way to find a username now, and this where statement literally makes no sense.
.Where(a=>Profile.UserName.Contains(UserName))
When you rearrange the Lambda expressions as Grant Winney's Answer shows you can see why most of the time a Select() is the last thing that normally happens (in simple queries).
I would wager there is no UserName on Profile. and you want to
string applyfor = db.Profiles
.Where(p => p.User.Any(u.UserName == UserName))
.Select(p => p.RoleID)
.First();
As a side note, Microsoft Best practice is to Camel-Case method parameters. So I would recommend your method look like:
public ActionResult GetRoles(string userName) // or username
{
}
Your Where statement should probably look more like this:
... .Where(a => a.UserName == Profile.UserName).FirstOrDefault();
Try this instead:
string applyfor = db.Profiles
.Where(x => x.UserName == UserName)
.Select(x => x.RoleID)
.First();
Also, if there's a chance you won't find a matching record, use FirstOrDefault() instead of .First() and then test for null.

Moq a retrieve of particular list item

I currently have such a Moq expression
repo.Setup(r => r.GetProjectConfigurationById(It.Is<int>(s => s == response.Id)))
.Returns(response); // return response only if id matches setup one
As one can see, response is an object that has its own Id field.
Now I have a List<responses> and would like to transfer this expression into something that behaves as such:
get any integer Id
if Id is mathcing a response.Id, return that element of a list.
optionally, if match is not found, return null
How I could do that with Moq?
You can use the It.IsAny<int>() to match any parameter in GetProjectConfigurationById
There are also overloads of the Returns function where you can specify your custom condition using the parameter passed in to your GetProjectConfigurationById to look up the element by id or return null:
var responses = new List<Response>();
//...
repo.Setup(r => r.GetProjectConfigurationById(It.IsAny<int>()))
.Returns<int>(id => responses.SingleOrDefault(r => r.Id == id));

Categories