Access list items by name to assign to variables - c#

I am sure the answer to this is everywhere but I am struggling to find it, perhaps I am not wording it correctly?
I have a list of items as shown:
What I want to then do is something like:
var phoneNo = res("phone_number").Value;
But what is the actual syntax?
EDIT:
Here's something I've tried to no success:

Looks like you are trying to get value from your claims. You can do so as below:
var userClaims = context.HttpContext.User as ClaimsPrincipal;
Get you claim value:
if (userClaims.Claims.Where(x => x.Type == "phone_number").FirstOrDefault() != null)
{
var phoneNumberClaim = User.Claims.Where(x => x.Type == "phone_number").FirstOrDefault().Value;
}

There is a special structure in programming for such tasks. It is called Dictionary.
I think your ToClaims method should return Dictionary, so you can access values by whatever key you want. Also you can cast your list using .ToDictionary(...), where you could split string by ":" for key and value.

From the feedback given I would like to show two of the best methods I took away from this.
The method I went with:
//set up a dictionary
var claims = ctx.User.ToClaims().ToDictionary(claim => claim.Type, claim => claim.Value);
//access as follows
var phoneNo = claims["phone_number"];
var firstName = claims["given_name"];
//etc.
Another good way:
//set up IEnumerable
var claims = ctx.User.ToClaims();
//access as follows
var phoneNos = claims.FirstOrDefault(c => c.Type == "phone_number")?.Value;
var firstName = claims.FirstOrDefault(c => c.Type == "given_name")?.Value;
//etc.

Related

dynamically define key name for which the value needs to be identified

I have a keyvalue pair list some thing like this
List<Subscriptions> subs = new List<Subscriptions>();
subs.Add(new Subscriptions() { Id = 1, Name = "ABC" });
subs.Add(new Subscriptions() { Id = 1, Name = "DEF" });
I can search against one key (ID or Name) but what I want to achieve is that user define which key they want to search against ID or Name
right now i am using this approach to filter the list based on Name Value
var filtered = subs.Where(sub => sub.Name.IndexOf(SearchString.Text,StringComparison.OrdinalIgnoreCase) >=0);
sub.Name is defined statically here, I want the user to choose what they want their search to be based on
for example if we have abc:Name program search for abc under Name key and if we have 1:Id then it search for 1 in ID.
This is just an example , in real scenario i can have multiple fields in my list.
I hope I am able to make myself clear.
Why you don't apply the Where by an simple if else or switch
// keyword : abc:Name or 1:Id
var value = keyword.Split(':')[0];
var key = keyword.Split(':')[1];
if(key == "Name")
{
var filterred = subs.Where(sub => sub.Name == value);
}
else if(key == "Id")
var filterred = subs.Where(sub => sub.id == int.Parse(value));
}
Fast answer:
string name = "";
int? id = null;
List<Subscriptions> subs = new List<Subscriptions>();
var query = subs.AsQueryable();
if (!string.IsNullOrEmpty(name))
query = query.Where(p => p.Name == name);
if (id.HasValue)
query = query.Where(p => p.id == id.Value);
var result = query.ToArray();
Detailed answer: you can read about expression tree and IQueryable interface
Basically you can avoid to cast your list to IQueryable if you not use something like Entity Frmework or OData. But if you need to convert you LINQ expression to something more complex - you should use IQueryable, or build your own expression tree.

Write attributes from list to var

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.

Linq queries in asp.net

I have this function below which is used to get those roles which are not already assigned. I have two list now.
One which has all the roles and the other one which has those roles which are already assigned to that user.
How do I return only those which are present in allRoles but not in alreadyHaveRoles?
public dynamic GiveRolesWhichAreNotAssignedToThisUser(String token, String selectedUser, String selectedOrganization)
{
User u = InstaFood.Core.User.Get(selectedUser);
var allRoles = RolesType.GetByOrganizationType(selectedOrganization).Select(i => new
{
ID = i.Id,
Name = i.Name
});
var alreadyHaveRoles = u.GetUserRoles().Select(i => new
{
ID = i.roleTypeId,
Name = ""
});
return ?? // what should be done here?
}
Can I compare them now given that both have same attributes now?
You can use Except to return the difference of two sequences, eg:
var difference=allRoles.Except(alreadyHaveRoles);
This assumes the two sequences contain items of the same type. The objects are checked for equality using their Equals implementation.
If you want to use your own equality comparison, you need to either have your objects implement IEquatable or create a custom EqualityComparer and use the Except overload that accepts a custom EqualityComparer.
In your case, you return two anonymous types that don't even have the same fields. A human would have to guess how to compare the two types, a computer will simply refuse to compile the code. If you consider two items equal if the IDs are equal, simply return the IDs, eg:
var allRoleIds = RolesType.GetByOrganizationType(selectedOrganization)
.Select(i => i.Id);
var assignedRoleIds = u.GetUserRoles().Select(i => i.roleTypeId);
var unassignedRoleIds=allRoleIds.Except(assignedRoleIds);
Retrieving the unassigned roles is trivial after that, just use:
var unassignedRoles=RolesType.GetByOrganizationType(selectedOrganization)
.Where(role=>unassingedRoleIds.Contains(role.Id);
public dynamic GiveRolesWhichAreNotAssignedToThisUser(String token, String selectedUser, String selectedOrganization)
{
User u = InstaFood.Core.User.Get(selectedUser);
var allRoles = RolesType.GetByOrganizationType(selectedOrganization).Select(i => new
{
ID = i.Id,
Name = i.Name
});
var alreadyHaveRoles = u.GetUserRoles().Select(i => new
{
ID = i.roleTypeId,
Name = ""
});
return allRoles.Where(i=>!alreadyHaveRoles.Contains(i));
}
Not tried but it should work

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.

C#: How to see if a Linq2SQL entity is in the database

I would like to check if an entity is already added to the database. So, how can I see this difference between a and b?
var a = dataContext.Things.First(x => x.Name == something);
var b = new Thing { Name = something };
To make it clearer, if I have this:
var thing = dataContext.Things.FirstOrDefault(x => x.Name == something)
?? new Thing { Name = something };
How can I see if thing needs to be inserted?
If you use FirstOrDefault instead of First, that will return null if there are no matches.
As for knowing whether you need to insert - just remember whether or not it was null to start with:
var a = dataContext.Things.FirstOrDefault(x => x.Name == something);
bool needsInsertion = (a == null);
a = a ?? new Thing { Name = something };
Alternatively, if there's an ID field in Thing which is automatically populated by the database, you can just use that to detect whether it's already in the database or not.

Categories