Write attributes from list to var - c#

I have the following piece of code:
var Attributes = db.Users.Where(u => u.UserId == PwRetreival.uId).Select(u => new { u.Name, u.UserId }).ToList();
user.Name = Attributes(SOMETHING?)
user.UserId = Attributes(SOMETHING?)
I have no idea how i would write the selected attributes to my model variables. I guess it doesn't know the type of the attribute when i write it like this?

This line returns a list of anonymous objects:
var Attributes = db.Users
.Where(u => u.UserId == PwRetreival.uId).Select(u => new { u.Name, u.UserId }).ToList();
Therefore, you can either iterate the list or index it:
user.Name = Atrributes[0].Name;
NOTE: Since you are getting the item by its Id, I would use Single or SingleOrDefault and not Where. See below for more.
Use Single
If you expect a single item to be returned, then do not use Where but use Single instead. Then you can do this:
user.Name = Attributes.Name;
Use SingleOrDefaut
If you expect a single item or no item, then use SingleOrDefault but check the value before using it like this:
if (Attributes != null)
{
user.Name = Attributes.Name;
}
There are also First, FirstOrDefault, Last and LastOrDefault.

As it is of type List, you need to use FirstOrDefault() to get the first record from the list (assuming that your Where clause have enough conditions to get the exact record you want).
var Attributes = db.Users.Where(u => u.UserId == PwRetreival.uId).Select(u => new { u.Name, u.UserId }).ToList().FirstOrDefault();
if (Attributes != null)
{
user.Name = Attributes.Name;
user.UserId = Attributes.UserId;
}

Attributes now is a list of an anonymous type containing Name and UserId.
user.Name = Attributes[0].Name
user.UserId = Attributes[0].UserId
... Would get the name and id of the first user, if the list contains at least 1 element.
You can also do:
foreach(var user in Attributes)
{
// var userName = user.Name;
// var userId = user.UserId;
}
... to iterate through all users. In this case, you don't even need the ToList() method in your query;
However, it seems like this query should return just one user. In this case, you can change your query to
var Attributes = db.Users.Where(u => u.UserId == PwRetreival.uId).Select(u => new { u.Name, u.UserId }).FirstOrDefault();
... and now Attributes has only 1 object with a Name and a UserId and you can access it like:
user.Name = Attributes.Name
user.UserId = Attributes.UserId
As pointed out by #Chris, if you can assume that your query is going to return 0 or 1 element, you should use SingleOrDefault(). If it should return just 1 element, you should use Single(). If the result contains more elements than it will throw an exception. And when you use XOrDefault you should always check for null afterwards.

Related

C# linq how to get property from predicate list when condition is met

I have the following linq query
var usersToNotify = trainingUsers.Where(x => delegatesToBeReminded.Any(d => d.UserGuid == x.UserGuid))
.Select(x => new RecipientDetail
{
FullName = x.FullName,
Email = x.Email,
// get property from delegatesToBeReminded
})
.ToList();
In the example above, i have trainingusers and delegatesToBeReminded list. i want to retrieve the matching record found in trainingusers and create custom type, with fullname, email from trainingusers and additional property from delegatesTobeReminded.
Can anyone help me how to do this?
Can i use something like this?
var x = from tu in trainingUsers
join d in delegatesToBeReminded on tu.UserGuid equals d.UserGuid
select new RecipientDetail
{
FullName = tu.FullName,
Email = tu.Email,
Session = d.Session
};
Thanks
Easiest would be to use a join, as you suggested:
trainingUsers.Join(
delegatesToBeReminded,
user => user.UserGuid,
delegateToBeReminded => delegateToBeReminded.UserGuid,
(user, delegateToBeReminded) => new RecipientDetail
{
FullName = user.FullName,
Email = user.Email,
Delegate = delegateToBeReminded,
});
(Or you can write the equivalent in linq query syntax, as you did).
Another way is to rewrite this in linq query syntax, using let:
from user in trainingUsers
let delegateToBeReminded = delegatesToBeReminded.FirstOrDefault(d => d.UserGuid == user.UserGuid)
where delegateToBeReminded != null
select new RecipientDetail
{
FullName = user.FullName,
Email = user.Email,
Delegate = delegateToBeReminded,
}
Note that these differ depending on what happens if there is more than one delegate for a particular user. The first creates a new RecipientDetail object for each user/delegate pair; the second creates a RecipientDetail object per user, and picks the first delegate.

How to Link two IDs from different classes in MVC5 to display certain information

I am trying to link up the RestaurantId in the RestaurantReservationEventsTbl with the RestaurantID in the RestaurantTbl to display reservations that are only made for the currently logged in restaurant.
I am receiving the following error in my code operator == cannot be applied to operands of type int and iqueryable int
Here is what I am doing in my home controller
var RestaurantIDRestaurantTbl = from r in db.Restaurants select r.RestaurantID;
//var listOfRestaurantsReservations = db.RestaurantReservationEvents.ToList();
var listOfRestaurantsReservations = db.RestaurantReservationEvents.Where(x => x.RestaurantID == RestaurantIDRestaurantTbl).ToList();
//return View(restaurants.Where(x => x.RestaurantEmailAddress == UserEmail).ToList());
//create partial view called _RestaurantReservation
return PartialView("_RestaurantReservations", listOfRestaurantsReservations);
You have to change your code to materialize the restaurantIds like this:
var RestaurantIDRestaurantTbl = (from r in db.Restaurants
select r.RestaurantID).ToList();
Then you may change the code as below for the comparison to work:
var listOfRestaurantsReservations = db.RestaurantReservationEvents.Where(x => RestaurantIDRestaurantTbl.Contains(x.RestaurantID)).ToList();
Anyway this is not the best solution. I will write another example for you, just try this example if it is working or not and let me know for the result.
I would considering changing the code as below to be much more efficient:
var listOfRestaurantsReservations = (from r in db.Restaurants
join e in db.RestaurantReservationEvents
on r.RestaurantID equals e.RestaurantID
//where r.RestaurantID == something //if where condition needed
select e).ToList();
If your tables are not connected with foreignkeys please consider to read this documentation here to make a better structure of the tables since they are related to each-other.
If your tables are related as in documentation article you might have something like that:
var RestaurantIDRestaurantTbl = db.Restaurants.SingleOrDefault(x => x.RestaurantID == something);
if(RestaurantIDRestaurantTbl != null)
{
var listOfRestaurantsReservations = RestaurantIDRestaurantTbl.RestaurantReservationEvents.ToList();
}
{
// This will give you a list of IDs
var RestaurantIDRestaurantTbl = db.Restaurants
.Select(p => p.RestaurantID)
.ToList();
// Using .Any() is a better choice instead of .Contains()
// .Contains is used to check if a list contains an item while .Any will look for an item in a list with a specific ID
var listOfRestaurantsReservations = db.RestaurantReservationEvents
.Where(p => RestaurantIDRestaurantTbl.Any(r => r.pRestaurantID == p))
.ToList();
}

LINQ - null exception on getting certain cell value

I'm a greenhorn when it comes to LINQ. I've read some null exceptions and most of them pointed out
... in sth.AsEnumerable() ...
as root of the problem.
I've run into:
The function evaluation requires all threads to run.
I tried to retrieve
fieldname
from TrashPlaces (it has 2 fields only - id and name) by string Id I get from UserPlace record (UserPlace has 2 keys - 1 is userId that can be retrieved from AspNetUsers and the other is TrashPlace id). I've run into null problem on this LINQ code:
public ActionResult JsonResult()
{
var users = db.AspNetUsers;
//this was added, so I could root out mismatch in the queryId
var nameformyuser = User.Identity.Name;
//the null starts here and no-shock it goes further (meaning query is null and
//can't do nothing later)
var queryId = from user in users.AsEnumerable()
where user.Email == User.Identity.Name
select user.Id;
var placerecord = db.UserPlace;
var userplace = from uplace in placerecord.AsEnumerable()
where uplace.usersId == queryId.ToString()
select uplace.placesId;
var places = db.TrashPlaces;
var field = from blah in places.AsEnumerable()
where blah.Id == userplace.ToString()
select blah.nameOfThePlace;
TempData["username"] = User.Identity.Name;
TempData["fieldname"] = field.ToString();
TempData["datename"] = DateTime.Now;
List<TrashViewModel> json = (List<TrashViewModel>)TempData["jsonList"];
return View(json);
}
Would be grateful for help and or/advice what's the best approach towards cascading LINQ.
Thanks!
You could do all in one (don't enumerate to early by the way, this is not good for performance).
Not sure why you use ToString() you shouldn't have to if your ids are of the same type.
var query = from u in db.AspNetUsers
join up in db.db.UserPlace on u.Id equals up.usersId
join tp in db.TrashPlaces on up.placesId equals tp.Id
where u.Email == User.Identity.Name
select tp.nameOfThePlace;//or more data if you need to.
var result = query.FirstOrDefault(); //or query.AsEnumerable()
Then you can do a null check
if (result == null)
In your case, for TempData, you may just do
TempData["fieldname"] = result == null ? string.Empty : result;
or
TempData["fieldname"] = result;
But then you'll have to check if TempData["fieldname"] is not null before using it.
...

Can SELECT and WHERE LINQ clause be combined?

Here is what I have done to Select users into my model and then remove all the null records:
model.Users = users
.Select(u =>
{
var membershipUser = Membership.GetUser(u.UserName);
return membershipUser != null
? new UserBriefModel
{
Username = u.UserName,
Fullname = u.FullName,
Email = membershipUser.Email,
Roles = u.UserName.GetRoles()
}
: null;
})
.Where(u => u != null)
.ToList();
Wondering if there is a way to combine the SELECT and WHERE clause.
I tried:
model.Users = users
.Select(u =>
{
var membershipUser = Membership.GetUser(u.UserName);
if (membershipUser != null)
return new UserBriefModel
{
Username = u.UserName,
Fullname = u.FullName,
Email = membershipUser.Email,
Roles = u.UserName.GetRoles()
};
})
.ToList();
But the intellisense suggest a syntax error. Which forces me to add a return null statement:
model.Users = users
.Select(u =>
{
var membershipUser = Membership.GetUser(u.UserName);
if (membershipUser != null)
return new UserBriefModel
{
Username = u.UserName,
Fullname = u.FullName,
Email = membershipUser.Email,
Roles = u.UserName.GetRoles()
};
return null;
})
.ToList();
So what is the correct way to write this SELECT statement so only valid records are selected into my model?
Conceptually you actually have three operations here:
project the user name to a membership user
filter out null membership users
project the membership users to a model
That is how your query should be looking. Your very first query has already tried to combine steps 1 and 3 together, but you're struggling because step two really should be in the middle of the two, and the hoops that you need to jump through to get around that aren't pretty.
The query actually becomes simpler and readable (and becomes idiomatic LINQ code) when you represent all three operations individually.
model.Users = users
.Select(user => new
{
user,
membershipUser = Membership.GetUser(user.UserName)
})
.Where(pair => pair.membershipUser != null)
.Select(pair => new UserBriefModel
{
Username = pair.user.UserName,
Fullname = pair.user.FullName,
Email = pair.membershipUser.Email,
Roles = pair.user.UserName.GetRoles()
})
.ToList();
This is a query that can also be written more effectively in query syntax:
model.Users = from user in users
let membershipUser = Membership.GetUser(user.UserName)
where membershipUser != null
select new UserBriefModel
{
Username = user.UserName,
Fullname = user.FullName,
Email = membershipUser.Email,
Roles = user.UserName.GetRoles()
};
As for the literal question of whether or not you can combine the projecting an filtering into a single LINQ operation, it is certainly possible. It would be an inappropriate solution to the problem, but the use of SelectMany can allow you to filter and project at the same time. This can be done by projecting the item to either a one item sequence containing the value that you want to project it to or an empty sequence based on the predicate.
model.Users = users
.SelectMany(u =>
{
var membershipUser = Membership.GetUser(u.UserName);
return membershipUser != null
? new[]{ new UserBriefModel
{
Username = u.UserName,
Fullname = u.FullName,
Email = membershipUser.Email,
Roles = u.UserName.GetRoles()
}}
: Enumerable.Empty<UserBriefModel>();
}).ToList();
Of course, every time you use this code, a kitten is killed. Don't kill kittens; use the earlier query instead.
I don't think this is possible, Select will map everything 1-1 as far as I know...if you're trying to filter you will need a Where.
edit edit:
I no longer believe SelectMany can do it (As Servy has shown).
I don't know about any Linq method which will allow you to arbitrary add or to not add the value into the resulting IEnumerable.
To do it the lambda(selector, predicate, filter...) should be able to control this addition. And only predicates(Where) are able to do it. In your case you will have to execute predicate(Where) and Select. There is no combinational method which will do both for you at the same time, except one non-direct method described in the end of the answer.
model.Users = users
.Where(u => Membership.GetUser(u.UserName) != null)
.Select(u =>
{
return new UserBriefModel
{
Username = u.UserName,
Fullname = u.FullName,
Email = Membership.GetUser(u.UserName).Email,
Roles = u.UserName.GetRoles()
};
})
.ToList();
We either get two Membership.GetUser(u.UserName) with such prefiltering or we will end with your original postfiltering.
That's just shifting the complexity. And it is difficult to say where the performance will be better.
It depends on whether the Membership.GetUser is fast and there are a lot of non-membership users - for my example. Or if Membership.GetUser is resource-consuming and there are few non-membership users your example with postfilter is better.
As any performance based decision it should be thoroughly considered and checked. In most cases the difference is minimal.
As it was already shown in the another post and pointed by Mr. 'Servy' it is possible to do so using one call of SelectMany SelectMany selecting either empty IEnumerable or 1-element array. But I still consider the first statement to be technically correct, because SelectMany returns collection of elements (it does not exactly add or doesn't add single element directly):
model.Users = users
.SelectMany(u =>
{
var membership = Membership.GetUser(u.UserName);
if (membership == null)
return Enumerable.Empty<UserBriefModel>();
return new UserBriefModel[]
{
new UserBriefModel()
{
Username = u.UserName,
Fullname = u.FullName,
Email = membership.Email,
Roles = u.UserName.GetRoles()
}
};
})
.ToList();
You can use a single method to accomplish this:
private IEnumerable<UserBriefModel> SelectUserBriefModels(IEnumerable<User> users)
{
foreach (var user in users)
{
var membershipUser = Membership.GetUser(user.UserName);
if (membershipUser != null)
{
yield return new UserBriefModel
{
Username = user.UserName,
Fullname = user.FullName,
Email = membershipUser.Email,
Roles = user.UserName.GetRoles()
};
}
}
}
You would use it like this:
model.Users = SelectUserBriefModels(users);
model.Users = users
.Where(u => u.Membership != null)
.Select(u => new UserBriefModel
{
Username = u.UserName,
Fullname = u.FullName,
Email = u.Membership.Email,
Roles = u.UserName.GetRoles()
})
.ToList();
First filter, then select. For this solution you need to have a navigation property so you can do u.Membership.Email instead of the membershipUser.Email.
My users look something like:
public class UserProfile
{
// other properties
public virtual Membership Membership { get; set; }
}
where Membership is the entity representing the membership table and is mapped via:
modelBuilder.Entity<Membership>()
.HasRequired<UserProfile>(m => m.User)
.WithOptional(u => u.Membership);
Then you can select everything with one query. Some other solutions here also work fine, but every call to Membership.GetUser(u.UserName) results in one additional DB call.

Join tables in NHibernate without mapping

I have the following two objects:
User
class User {
public int role;
}
Role
class Role {
public int id;
public string name;
}
be note that role property inside User is int and not Role, that's our limitations.
I want to join between all the users and each of his role. In the mapping objects there is no reference as you can understand, just a simple type (int).
How do I do that join statement?
It's called a theta join:
var a = (from u in session.Query<User>()
from r in session.Query<Role>()
where u.role == r.id
select new { u.Username, Role = r.name }).ToList();
Assuming you have a Username property on the User class.
Yes, this "theta join" (as I just learned this term) is very handy and let's us not worry about putting in pointless mapping relationships.
WARNING HOWEVER IN USING THIS!!! This tripped me up a lot.
Adding to the above example...
var list = new List<int>( { 2, 3 } ); // pretend in-memory data from something.
var a =
(from u in session.Query<User>()
from x in list
from r in session.Query<Role>()
where u.role == r.id
where r.id == x.id // pretend list wants to limit to only certain roles.
select new { u.Username, Role = r.name }).ToList();
THIS WILL BOMB with some NotSupported exception.
The trick is that anything coming from NHibernate Session must come LAST. So this alteration WILL work:
var a =
(from x in list
from u in session.Query<User>()
from r in session.Query<Role>()
where u.role == r.id
where r.id == x.id // pretend list wants to limit to only certain roles.
select new { u.Username, Role = r.name }).ToList();
And and BTW, you can use join as well, however you have to make sure if you have any nullable data types, that you use the .Value if you are joining to something not-nullable.
var a =
(from x in list
from u in session.Query<User>()
join r in session.Query<Role>() on u.role equals r.id
where r.id == x.id // pretend list wants to limit to only certain roles.
select new { u.Username, Role = r.name }).ToList();
And while we're at it, let's say you have a method that has some dynamic condition. In this example the 'list' which could be a list of roles to filter by, but don't filter at all if the list is not there. Well, if you do the .ToList() then you are causing this query to execute immediately. But instead you can add a condition and then execute it later:
var a =
from u in session.Query<User>()
join r in session.Query<Role>() on u.role equals r.id
where r.id == x.id // pretend list wants to limit to only certain roles.
select new { u.Username, Role = r.name, RoleID = r.id }; // Adding the Role ID into this output.
if (list != null) // assume if the list given is null, that means no filter.
{
a = a.Where(x => list.Contains(x.RoleID));
// WARNING. Unfortunately using the "theta" format here will not work. Not sure why.
}
var b = a.ToList(); // actually execute it.
var c = a.Select(x => new { x.Username, x.Role }).ToList() // if you insist on removing that extra RoleID in the output.
One last thing.. Sometimes some simple logic will fail when executed in the select new { .. } part. I don't have an explanation. In our case the logic was just converting a DB value of a uint to an Enumerator of a model. But to get around that, I just avoided doing that conversion while reading the data but saved the value. Then in a later step, after the data was loaded, I just did the conversion in another LINQ statement.
DISCLAIMER: While I wrote many of these things all the past several weeks, I did not put this code into my compiler to verify 100%.

Categories