I have this function that returns 2 strings
public object GetNamePhoneByUserId(int userId)
{
return _db.ApplicationUsers.Where(q => q.UserId == userId).Select(a => new {
a.FullName,a.PhoneNumber}).ToList();
}
When calling the function, i'm getting the values, but unable to extract them from the returned value(appU)
object appU = _unitOfWork.ApplicationUser.GetNamePhoneByUserId(ca.UserId);
i was able to cast it to Ienumerable but still can't extract the values..
IEnumerable list = (IEnumerable)appU;
I'm sure its a simple solution, but tried many things and still not working.
Thank you
Don't say that your method returns an object. You're going to have a really tough time working with the data, as you've seen.
Instead, create a class to represent the fields you're returning, and return a collection of that class.
public class ApplicationUserMinimalInfo // make this more descriptive as needed
{
public string FullName { get; set;}
public string PhoneNumber {get; set;}
}
public List<ApplicationUserMinimalInfo> GetNamePhoneByUserId(int userId)
{
return _db.ApplicationUsers
.Where(q => q.UserId == userId)
.Select(a => new ApplicationUserMinimalInfo
{
a.FullName,
a.PhoneNumber
}).ToList();
}
Now, I also suspect that because you're filtering by the UserId, you should only be getting a single result back, or no results back. It doesn't make sense to get two records with the same UserId.
public ApplicationUserMinimalInfo? GetNamePhoneByUserId(int userId)
{
var user = _db.ApplicationUsers
.SingleOrDefault(q => q.UserId == userId); // uses "Where" logic
if (user is null)
return null;
else
return new ApplicationUserMinimalInfo
{
user.FullName,
user.PhoneNumber
});
}
Now, unless you really have some super pressing reason to have a method that returns a subset of properties, just return the full object.
public ApplicationUser? GetUserById(int userId)
{
return _db.ApplicationUsers
.SingleOrDefault(q => q.UserId == userId);
}
Or better yet, this method is a single line, it doesn't really need to be its own method.
Related
So I read that it is bad design to have an interface parameter be checked as sending in an interface member is supposed to associate itself as an contract that the only the interface members are going to be used. As such I thought to simply overload the method. This seems like it would quickly spiral out of control however if multiple objects that implement the interface needs different implementations of the method.
public IArtist FindArtist(IArtist artist)
{
var activeArtist = _database.Artists.FirstOrDefault(a => a.Name == artist.Name);
return activeArtist;
}
public IArtist FindArtist(SpotifyArtist artist)
{
var spotifyArtists = _database.Artists.Where(a => a is SpotifyArtist).Cast<SpotifyArtist>();
SpotifyArtist activeArtist = spotifyArtists.FirstOrDefault(a => a.Name == artist.Name && a.SpotifyID == artist.SpotifyID);
return activeArtist;
}
In the above code snippet, when I need to call the FindArtist with a SpotifyArtist object (which implements IArtist), the function should look for an object that has the same Name and also SpotifyID. Whereas if it is any other type of IArtist, it is to just return based on the name (probably will modify it to prioritize non-SpotifyArtist objects later). Do you have any suggestions to what I should be doing here instead?
EDIT TableImplementation:
public class MusicObjectTable
{
public List<IArtist> Artists;
public List<IAlbum> Albums;
public List<ITrack> Tracks;
public MusicObjectTable()
{
this.Artists = new List<IArtist>();
this.Albums = new List<IAlbum>();
this.Tracks = new List<ITrack>();
}
public MusicObjectTable(List<IArtist> artists, List<IAlbum> albums, List<ITrack> tracks)
{
this.Artists = artists;
this.Albums = albums;
this.Tracks = tracks;
}
}
}
OK this is not directly answering your question, because I think it might be a little XY.
However, this is what I'd do, let relational data be relational data. I.e use a relational database.
Artists are a key concept, there is only of them. Make an Artists table.
One Artist may have multiple Spotify accounts, so we might need a Spotify table to hold things like urls, band name, pictures, whatever… I mean one Artist can be in multiple bands right. So the solve here is to have a one-to-many relationship with Artist to Spotify.
You could have the same with YouTube, one artist could have many videos. One-to-Many again.
Every time you need to add more connections (relationships) you just add a new table, you don’t have to expand on the one table (you don't have to keep adding loosely-related junk to the artist table) the only thing you need to add (if you wanted is a navigation collection property).
An example usage is this in a simple pseudo-code way
var artist = db.Include(x => x.SpotifyAccounts)
.Include(x => x.YouTubeVideos)
.Include(x => x.EbayStores)
.FirstOrDefault(x => x.Name == SearchName);
Console.WriteLine(artist.Name);
if(artist.SpotifyAccounts.Any)
foreach(var item in artist.SpotifyAccounts)
Console.WriteLine(" -- " + item.Url);
var spotify = db.SpotifyAccounts
.Include(x => x.Arists)
.FirstOrDefault(x => x.Id == SpotifyId);
Console.WriteLine(spotify.Id);
Console.WriteLine(spotify.Url);
Console.WriteLine(spotify.Artist.Name);
Note: This does away with your search methods and your inheritance and replaced with relationships. What are the down sides? Well not everything is in the one table, inheritance is really not an option. The pros are, as your models become more complex you just add relationships, you can add as many as you like, which actually doesn't touch your Artist table (unless it's one to one).
When searching for an Artist name, you have access to everything they have. if you search for a particular Spotify account you always have access to the Artist.
However this really depends how far you want to go down the rabbit-hole. If this is going to be any kind of system, I think relational is the way to go. It's scalable, and it's self consistent and it's how most large systems work.
It would be bad form if IArtist behaved differently for different types. It's OK if the implementation is different, and it does different things behind the scenes; it is not OK if the functional behavior differs when viewed as a black box. The contract promises something, and it ought to be consistent.
If you happen to be writing code where you know you have a SpotifyArtist, you also know you can call a different method, if you want to.
public IArtist FindArtistByName(IArtist artist)
{
var activeArtist = _database.Artists.FirstOrDefault(a => a.Name == artist.Name);
return activeArtist;
}
public IArtist FindArtistByNameAndID(SpotifyArtist artist)
{
var spotifyArtists = _database.Artists.Where(a => a is SpotifyArtist).Cast<SpotifyArtist>();
SpotifyArtist activeArtist = spotifyArtists.FirstOrDefault(a => a.Name == artist.Name && a.SpotifyID == artist.SpotifyID);
return activeArtist;
}
And you can also provide a convenience method:
public IArtist FindArtistByBestMethod(IArtist artist)
{
if (artist is SpotifyArtist)
{
return repo.FindArtistByNameAndID((SpotifyArtist)artist);
}
else
{
return repo.FindArtistByName(artist);
}
}
An answer using filters:
The filter:
public ArtistFilter
{
public string SearchString { get; set; }
public Type? Type { get; set; }
public int? MinimumRating { get; set; }
}
MinimumRating is just to show you how to extend the filter easily.
Secondly you have a method that converts the filter into a function:
private static Expression<Func<IArtist, bool>> CreateArtistFilterExpression(ArtistFilter filter)
{
Expression<Func<IArtist, bool>> expression = x => true;
if(filter == null)
{
return expression;
}
if(!string.IsNullOrWhiteSpace(filter.SearchString))
{
expression = expression.And(x => x.Name.Contains(filter.SearchString));
}
if(filter.Type != null)
{
expression = expression.And(x => x is Type.Value);
}
if(filter.MinimumRating != null)
{
expression = expression.And(x => x.Rating >= filter.MinimumRating);
}
return expression;
}
The And-extension-method is pretty small:
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2) {
var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
return Expression.Lambda<Func<T, bool>>(Expression.AndAlso(expr1.Body, invokedExpr), expr1.Parameters);
}
A last method reduces redundant code:
public List<IArtist> GetArtistsByFilter(ArtistFilter filter)
{
var expression = CreateArtistFilterExpression(filter);
return _database.Artists.Where(expression).ToList();
}
And you can get the best matching one like this:
var filter = new ArtistFilter {
SearchString = "Lennon",
Type = typeof(SpotifyArtist)
};
var matchingArtists = GetArtistsByFilter(filter);
var bestMatching = matchingArtists.FirstOrDefault();
You ignore the rating then. By setting the MinimumRating as well you can also filter for only-good artists.
Note: I typed most of this in stackoverflow, so I might have missed a semicolon or so.
i struggling to find the correct way to query for a specific entity in my database. I have a table TeamMember which looks as follows:
public class TeamMember
{
public Guid TeamId { get; set; }
public Guid ManagerUserId { get; set; }
...
}
At several positions i want to query for a "TeamManager" in my teams.
public TeamMember GetTeamManager(Guid teamId, List<TeamMember> teamMembers)
{
return teamMembers.FirstOrDefault(member => member.TeamId == teamId && member.ManagerUserId == null);
}
If i want to use a method in an expression e.g (not real code),
...
// IQueryable<TeamMember>
teamMembers.Where(member => member.team.GetTeamManager(teamId, teamMembers))
it works fine for in memory objects, but this does not work in combination with the entity framework, so real db objects.
Therefore i was experimenting with static expressions, but i did not find any solution which uses a static expression in combination with a variable e.g.:
// this should be an ideal solution
Expression<Func<TeamMember, bool>> exp = teammember => teamMember.TeamId == **CUSTOM_VARIABLE** && teamMember.ManagerUserId == null;
teamMembers.Where(exp)
I want to reuse the expression, but i also want to be able to modify the variable. My goal is to avoid the creation of an object in between because the following would work, but is less efficient (correct me if i'm wrong)
teamMembers.ToList().Where(member => member.team.GetTeamManager(teamId, teamMembers))
So please help me with my problem :).
Thank you in advance!
You can't make exp a property because of the need to capture a variable, but you can make it a function returning Expression<Func<TeamMember,bool>>:
Expression<Func<TeamMember,bool>> MakeMemberExpression(Guid teamId) {
return teammember => teamMember.TeamId == teamId && teamMember.ManagerUserId == null;
}
or even
Expression<Func<TeamMember,bool>> MakeMemberExpression(Guid teamId) =>
teammember => teamMember.TeamId == teamId && teamMember.ManagerUserId == null;
You can use it as follows:
var members = teamMembers.Where(MakeMemberExpression(teamId));
You can create a function that operates on IQueryable.
public TeamMember GetTeamManager(IQueryable<TeamMember> baseQuery,Guid teamId)
{
return baseQuery.FirstOrDefault(member => member.TeamId == teamId && member.ManagerUserId == null);
}
Getting this error
"System.Linq.Enumerable+WhereSelectEnumerableIterator`2[Person.Models.IProfession,System.String]"
Code is below: I am trying to have a collection of result. Service returns me collection I think and I need to iterate through and store as a list which will have that collection. Please help me
public class ProfessionResult
{
public string Name { get; set; }
public string ID{ get; set; }
}
public List<ProfessionResult> ProfessionResults
{
get
{
var professionResults = new List<ProfessionResult>();
professionResults.Add(new ProfessionResult()
{
Name = People?.Where(p => p.IsSelected)
.Select(c => c.ProfessionResults.Select(n => n.Name))
.ToString() ?? null,
ID = People?.Where(p => p.IsSelected)
.Select(c => c.ProfessionResults.Select(i => i.ID))
.ToString() ?? null
});
return professionResults;
}
}
A basic google search on your partial error message revealed this post:
Linq query on Xdocument returns "System.linq.Enumerable+WhereSelectEnumerableIterator'2[system.XML.Linq.Xelement,System.String]
According to it,
Yes, that's because you've calling ToString() directly on a query for
your second and third values.
Basically, don't call ToString() on queries. If you want a single
value, use Single(), First() etc. If you want multiple values, iterate
over them and do what you want with each of them in turn - or join
them together in some appropriate fashion.
Which means you will have to store the values as their initial format and not use ToString() on them inside the linq query.
*Edit**
For example, you could try:
Name = People?.Where(p => p.IsSelected).Select(c => c.ProfessionResults.Select(n => n.Name)).Single().ToString() ?? null,
ID = People?.Where(p => p.IsSelected).Select(c => c.ProfessionResults.Select( i => i.ID)).Single().ToString() ?? null
But only if you know for sure that you will return a single unique record with p => p.IsSelected every time.
I haven't tested it, so let me know if it works.
Here is what I want to do:
var user = db.User.First(conditions);
user.Book.First();
Here is currently how I have to do that.
var user = db.User.Include("Book").First(conditionsForUser);
user.Book.First();
The reason why I want to simplify this, is because I don't want to have to specify what is included every time I want to access a relationship. Seems very cumbersome.
e.g.: I would like to just be able to do the following, given I have previously retrieved a user:
user.Book.First()
user.Blog.First()
user.SomeOtherHasManyRelationship.Where(conditions)
Here is what I have so far:
public object RelationshipFor(string relationship)
{
using (var db = User.DbContext())
{
var relationshipType = TypeRepresentedBy(relationship); // unused for now, not sure if I need the type of the relationship
var myTable = ((ICollection)db.Send(RelationshipName)); // RelationshipName is "User" in this instance.
var meWithRelationship = myTable.Where(i => i.Send(IdColumn) == Id).Include(relationship); // currently, myTable doesn't know about 'Where' for some reason.
return meWithRelationship.Send(relationship);
}
}
And then how that would be used would be the following:
user.RelationshipFor("Book") // returns a list of books
I have some other logic in my code which abstracts that further which would allow me to do user.Book.First().
Hopefully I can get permission to open source a lot of this, as I'm modelling a lot of the api after ActiveRecord-style crud.
Note, that I'm using I set of extensions I made to help dealing with dynamicness less painful: https://github.com/NullVoxPopuli/csharp-extensions
UPDATE 1:
public object RelationshipFor(string relationship)
{
using (var db = User.DbContext())
{
var myTable = (DbSet<DatabaseModels.User>)db.Send(RelationshipName);
var myInclude = myTable.Include(i => i.Send(relationship));
var meWithRelationship = myInclude.First(i => (long)i.Send(IdColumn) == Id);
return meWithRelationship.Send(relationship);
}
}
For now, I've hard coded the cast of the user in an attempt to just get something working.
My error now is:
Unable to cast object of type 'System.Linq.Expressions.MethodCallExpressionN' to type 'System.Linq.Expressions.MemberExpression'.
This is not a trivial problem, and there's no "one size fits all" approach. What you actually seem to be after is lazy loading, which was not included in EF7 for many reasons.
I don't know what the code you show is supposed to do, but one option would be to introduce a repository pattern, where you specify the "entities to include" at the collection level:
public class UserRepository
{
private readonly IQueryable<User> _dataSet;
public UserRepository(IQueryable<User> userDataSet)
{
_dataSet = userDataSet;
}
public IQueryable<User> Include()
{
return _dataSet.Include(u => u.Book)
.Include(u => u.Blog);
}
}
And you can move lots of the logic to a generic base class, leaving you with just the Include() method. You can for example work with strings as you show (or enums, or ...), to only select related entities to include:
public class GenericRepository
{
// ...
public IQueryable<User> Include(string includeGroup = null)
{
return IncludeGroup(includeGroup);
}
protected virtual IncludeGroup(string includeGroup)
{
return _dataSet;
}
}
And then in UserRepository:
protected override IQueryable<User> IncludeGroup(string includeGroup)
{
switch (includeGroup.ToUpperInvariant())
{
case "BOOK":
return _dataSet.Include(u => u.Book)
.Include(u => u.Book.Author);
case "BLOG":
return _dataSet.Include(u => u.Blog);
default:
return base.Include(includeGroup);
}
}
And then use it like this:
var userRepo = new UserRepository(db.User);
var userWithBooks = userRepo.Include("Book");
var firstUser = userWithBooks.FirstOrDefault(u => u.Name == "Foo");
var firstUserFirstBook = firstUser.Book.FirstOrDefault();
One alternative would be to always include all navigation properties (recursively), but that would be a horrible approach in terms of query efficiency, as every query will be one massive join to all related tables, whether that is necessary or not.
I have List of List of Permissions i.e. List<List<Permission>> permisionLists and each permission has property called HasPermission.
Each list of permission is identical except HasPermission property true/false for permission item.
What is the most efficient way to find out list of Permissions which has all HasPermission set to false in in permisionLists?
I have to find only permissions which has value set to false in every List.
public class Permission
{
public Guid Id { get; set; }
public string Action { get; set; }
public bool HasPermission { get; set; }
}
I have tried below code but no luck,
disabledPermissions = from permisions in permisionLists
from permission in permisions
where permisionLists.All(l => l.Any(o => o.HasPermission ==false))
orderby permission.HasPermission
select permission;
Edited once again: this should give you an idea on how you could filter the lists to search for the same id. This is likely not the best performance-oriented approach, but it should give you an idea:
permisionLists.ForEach(permissions => permissions.Where(p => !p.HasPermission).ToList().ForEach(permission =>
{
if (!permisionLists.Where(permissionList => permissionList.Where(p => p.Id == permission.Id).FirstOrDefault().HasPermission).Any())
{
disabledPermissions.Add(permission);
}
}));
The ForEach method executes the lambda expression for each item in the list. This filters explicitly only items in the list that has HasPermission set to false.
If I understand correctly your question, the following will be a quite effective way to achieve the goal with linear time complexity
var itemMap = new Dictionary<Guid, Permission>();
foreach (var list in permissionLists)
{
foreach (var item in list)
{
Permission other;
if (!itemMap.TryGetValue(item.Id, out other) || (item.HasPermission && !other.HasPermission))
itemMap[item.Id] = item;
}
}
var result = itemMap.Values.Where(item => !item.HasPermission).ToList();
The same can be achieved with Linq, but will use more space due to groupings storage allocation
var result =
(from list in permissionLists
from item in list
group item by item.Id into g
where !g.Any(item => item.HasPermission)
select g.First()).ToList();
I personally prefer the former (non Linq).
You use the word 'efficient' in your question. You will want to ask a question of the List and make sure that is only recalculated of the list content changes.
I'd consider creating a new class like so;
public class PermissionCollection : Collection<Permission>
{
}
Override the InsertItem, RemoveItem methods etc as shown in example 2 of this MSDN page. Set a private Boolean like collectionDirty to true on any edit
Then add another property like
public bool HasAnyPermissions
{
get
{
if (collectionDirty) {
// recalculate here
cachedAnswer = ...;
collectionDirty = false;
}
Return cachedAnswer;
}
}
This gives you a very effective way to make sure you're not performing an O(n^2) search, which the current suggestions suffer from.
I have modified cFrozenDeath answer as in his case I am getting duplicate permissions
permisionLists.ForEach(permissions => permissions.Where(p => !p.HasPermission).ToList().ForEach(permission =>
{
if (!permisionLists.Where(permissionList => permissionList.Where(p => p.Id == permission.Id).FirstOrDefault().HasPermission).Any())
{
if (disabledPermissions.All(p => p.Id != permission.Id))
disabledPermissions.Add(permission);
}
}));