i have a problem with linq, i have the following code:
Models.Users user = null;
foreach (var item in db.Users)
{
if (item.username.Equals(username))
{
ausgabe = true;
user = item;
}
}
// linq, does not work
user = null;
var test = from u in db.Users
where u.username.Equals(username)
select u;
user = (Models.Users)test;
at the runtime i get a error because test i IQueryable, but how to make this conversation?
It looks like the problem is casting a query to a user, when you want to execute the query, so probably:
user = test.SingleOrDefault();
(see also FirstOrDefault(), First(), and Single())
Also, for convenience and readability, can I suggest:
where u.username == username
(which also, in regular code, avoids the problem of u.username being null, and thus causing a NullReferenceException)
Your cast is wrong, you want assign a list of objects to one object:
var test = from u in db.Users
where u.username.Equals(username)
select u;
user = (Models.Users)test; // wrong part.
Do
user = test.FirstOrDefault();
Or
user = db.Users.FirstOrDefault(x=>x.username.Equals(username));
Related
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.
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.
...
The code below works for cases where there are already records in the Credit card table for the user who is logged in; however, when a user doesn't have an entry in the credit card table, the query finds zero records as expected. The problem is, the statement maxccid = query.Maxccid(); returns a Null and an InvalidOpeation exception is thrown. I can't make the ccid field in the database nullable as it is part of a primary key. I need a way to detect if this query will return a null before I run it, or a way to trap it (preferably without a try catch, as this condition will happen for every new customer (Best practices for Try/Catch state this is not a proper use of Try/Catch). Just a note to add that I'm using Entity Framework.
UPDATE 4/9/14: I modified the query to fix the problem I reported in comments to Usesr FailedProgramming and Mike. I still have the null problem though.
// Create CreditCard - Write to DB
public ActionResult Create(CreditCard model)
{
EntitiesContext context = new EntitiesContext();
int uid = (int)WebSecurity.GetUserId(User.Identity.Name); // Currently logged-in user
short? maxccid = 0; //this will be the max ccid for this user
var query = from c in context.CreditCards
where c != null && c.UserId == uid select c.CCID;
maxccid = query.Max();
if(query.Any())
maxccid = query.Max();
First of all use using for the databse objects.
Secondly, use null-coalescing operator. for handling the null Check here http://msdn.microsoft.com/en-us/library/ms173224.aspx
public ActionResult Create(CreditCard model)
{
using(EntitiesContext context = new EntitiesContext()) // using keyword will dispose the object properly.
{
int uid = (int)WebSecurity.GetUserId(User.Identity.Name); // Currently logged-in user
short? maxccid = 0; //this will be the max ccid for this user
var query = from c in context.CreditCards
where c.UserId == uid && c.CCID == (context.CreditCards.Max(c1 => c1.CCID) ) select c.CCID ;
maxccid = query.Max() ?? 0; //use null-coalescing operator.
}
}
You can optimize this code more as per your needs.
Hope, It may help you at some point. Have a nice day.
I have 2 Databases using EF w/ MVC4. I have searched all through SO to avail. I need to return a list of Alerts to a partial view. However the Alerts should be filtered by a specific username with a specific identifier. The View is strongly typed, and I'd like to keep it like that.
I have the LINQ query returning to a List and it's the list of the usernames associated with the specific id. You can see in the second case statement where the two table lookup needs to go.I want to do this without a viewmodel class.
Here is the code:
public PartialViewResult DashboardAlerts()
{
Database.SetInitializer<AlertsContext>(null);
AlertsContext db = new AlertsContext();
Database.SetInitializer<MemberUsersContext>(null);
MemberUsersContext mdb = new MemberUsersContext();
var members = new List<MemberUsers>(mdb.MemberUsers);
var alerts = new List<Alerts>(db.Alerts);
var query = from x in alerts
join y in members
on x.username equals y.username
where y.clubID == (int)Session["ClubID"]
select new { username = y.username};
var list = query.ToList();
switch (Session["RoleName"].ToString())
{
case "GMC Admin": return PartialView(db.Alerts.ToList());
case "Club Admin": return //return db.Alerts.ToList() that has only usernames from query.ToList();
default: return PartialView(db.Alerts.Where(x => x.username == User.Identity.Name).ToList());
}
}
Bottom Line: I want to cross reference db.Alerts with only values from query list's username property.
From your question, you use want to narrow down the alerts to the ones where you have the usename in query. looks like you already have that done, just dont select the username, but the alert instead
var query = from x in alerts
join y in members
on x.username equals y.username
where y.clubID == (int)Session["ClubID"]
select x;
that will return you the alerts rather than the list of usernames.
I have a simple database with two tables. Users and Configurations. A user has a foreign key to link it to a particular configuration.
I am having a strange problem where the following query always causes an inner join to the Configuration table regardless of the second parameter value. As far as I can tell, even though the "UserConfiguration =" part of the object initialisation is conditional, LINQ doesn't see that and determines that a relationship is followed in any case.
If I actually remove that last initialisation, the whole thing works as expected. It doesn't inner join when loadConfiguration == false and it does join when loadConfiguration == true.
Anyone got any ideas about this? Is this syntax just not going to work? The only thought I have now is to wrap the return in a basic if statement - I just wanted to avoid the duplicated lines.
public UserAccount GetByUsername(string username, bool loadConfiguration)
{
using (Database database = new Database())
{
if (loadConfiguration)
{
DataLoadOptions loadOptions = new DataLoadOptions();
loadOptions.LoadWith<User>(c => c.Configuration);
database.LoadOptions = loadOptions;
}
return (from c in database.Users
where c.Username == username
select new UserAccount
{
ID = c.ID,
ConfigurationID = c.ConfigurationID,
Username = c.Username,
Password = c.Password.ToArray(),
HashSalt = c.HashSalt,
FirstName = c.FirstName,
LastName = c.LastName,
EmailAddress = c.EmailAddress,
UserConfiguration = (loadConfiguration) ? new ApplicationConfiguration
{
ID = c.Configuration.ID,
MonthlyAccountPrice = c.Configuration.MonthlyAccountPrice,
TrialAccountDays = c.Configuration.TrialAccountDays,
VAT = c.Configuration.VAT,
DateCreated = c.Configuration.DateCreated
} : null
}).Single();
}
}
Thanks in advance,
Martin.
I dont think it will work like that.
I suggest splitting it into 2 distinct queries.
There are probably better ways, but it would require more 'plumbling'.
Nope, this will not work. I've run into similar issues many times. The reason for that has to do with expressions at compile time vs. conditions at run-time.
You could do 2 queries or if you don't mind joining to configuration regardless of loadConfiguration parameter, you could use:
var q = (from c in database.Users
where c.Username == username
select c).Single();
and then use Linq-to-Objects on the result.
Replace .Single() with SingleOrDefault() and Linq will switch to a left outer join. I don't know if in your case it will do it, but in some cases it does.
Edit dint's see the Single was for the entire query and not for the configuration part:
try this:
UserConfiguration = (loadConfiguration && c.Configuration != null) ? new ApplicationConfiguration
{
ID = c.Configuration.ID,
MonthlyAccountPrice = c.Configuration.MonthlyAccountPrice,
TrialAccountDays = c.Configuration.TrialAccountDays,
VAT = c.Configuration.VAT,
DateCreated = c.Configuration.DateCreated
} : null