Linq - drill down with find - linq

I am completely new to linq and need help.
These are my poco classes:
public class User {
public User()
{
this.Profiles = new List<Profile>();
}
public Guid ID { get; set; }
public bool IsValid{ get; set; }
public virtual ICollection<Profile> Profiles { get; set; }
}
public class Profile {
public Profile() {
this.Users = new List<User>();
this.Customers = new List<Customer>();
}
public Guid ID { get; set; }
public string Name { get; set; }
public virtual ICollection<User> Users { get; set; }
public virtual ICollection<Customer> Customers { get; set; }
}
public class Customer {
public Customer()
{
this.Profiles = new List<Profile>();
}
public Guid ID { get; set; }
public string Number { get; set; }
public virtual ICollection<Profile> Profiles { get; set; }
}
I would like to search for valid Users with special customers. Special customers would come from another user. So I would send another user as method argument.
Is it even possible with linq or I need stored procedure to solv the problem?
Best regards

You can try this:
public static List<User> FindAllUsersBySameCustomers(User sourceuser)
{
var res = sourceuser.Profiles.SelectMany(p => p.Customers)
.SelectMany(c => c.Profiles)
.SelectMany(p => p.Users)
.Distinct();
return res.ToList();
}
But beware, it will work only if your relations are populated (included) like in my example here.
NOTE
You should not call virtual member inside the constructor. Anwer is here on SO: Virtual member call in a constructor

Try this..
/// <summary>
/// Search for valid Users with special customers.
/// Special customers would come from another user.
/// So I would send another user as method argument.
/// </summary>
/// <returns></returns>
public List<User> FindValidUsersWithSpecialCustomers(List<User> allUsers, User anotherUser)
{
var specialCustomers = anotherUser.Profiles.SelectMany(aProfile => aProfile.Customers);//.Select(cust => cust.Number == "SpecialCustomerNumber" && cust.ID == new Guid("SpecialCustomerGuid"));
Func<IEnumerable<Customer>, IEnumerable<Customer>, Boolean> IsSpecialCustomersPresentInThisCustomersList =
delegate(IEnumerable<Customer> customerList, IEnumerable<Customer> specialCustomersList)
{
if ((from cust in customerList where specialCustomersList.Contains(cust) select cust).Any())
return true;
else
return false;
};
var validUsersWithSpecialCustomers = (from user in allUsers where user.IsValid && IsSpecialCustomersPresentInThisCustomersList(user.Profiles.SelectMany(p => p.Customers), specialCustomers) select user);
return validUsersWithSpecialCustomers.ToList();
}

Related

InvalidCastException: Unable to cast object of type 'System.Collections.Generic.List to System.Collections.Generic.IEnumerable

I am trying to implementation clean architecture in netcore and I have Runtime Error
InvalidCastException: Unable to cast object of type 'System.Collections.Generic.List to System.Collections.Generic.IEnumerable
In the WebUI I have Match controller and ViewAllMatch Action like this
public async Task<IActionResult> ViewAllMatch()
{
var matches = await _mediator.Send(new GetMatchesDetail());
return View(matches);
}
In the application Layer I have A queries like this:
public class GetMatchesDetail : IRequest<IEnumerable<MatchesDetail>>
{
}
public class MatchesDetail
{
public string MatchId { get; set; }
public int MatchNumer { get; set; }
public DateTime DateMatch { get; set; }
public TimeSpan TimeMatch { get; set; }
public int MatchYear { get; set; }
public string SeasonId { get; set; }
public string Round { get; set; }
/// <summary>
/// Set value to Qualified for Qualified and Final for Final Round
/// </summary>
public string Stage { get; set; }
public string SubStage { get; set; }
public string HTeam { get; set; }
public string HTeamCode { get; set; } //For Flag get from Table Team from Foreign Key TeamName
public int HGoal { get; set; }
public int GGoal { get; set; }
public string GTeam { get; set; }
public string GTeamCode { get; set; }
public string WinNote { get; set; }
public string Stadium { get; set; }
public string Referee { get; set; }
public long Visistors { get; set; }
public string Status { get; set; }
}
public class GetMatchesHandler : IRequestHandler<GetMatchesDetail, IEnumerable<MatchesDetail>>
{
private readonly IMatchRepository _matchRepository;
public GetMatchesHandler(IMatchRepository matchRepository)
{
_matchRepository = matchRepository;
}
public async Task<IEnumerable<MatchesDetail>> Handle(GetMatchesDetail request, CancellationToken cancellationToken)
{
var matchlistview = await _matchRepository.GetMatchDetailAsync();
return matchlistview;
}
}
And the code for matchRepository to get all the match in Infastructure like this.
public async Task<IEnumerable<MatchesDetail>> GetMatchDetailAsync()
{
var matchDetailList = (from match in _context.Matches
join team1 in _context.Teams on match.HTeam equals team1.TeamName
join team2 in _context.Teams on match.GTeam equals team2.TeamName
join season in _context.Seasons on match.SeasonId equals season.SeasonId
select new
{
match.MatchId,
match.MatchNumber,
match.DateMatch,
match.TimeMatch,
match.MatchYear,
match.SeasonId,
season.SeasonName,
match.Round,
match.Stage,
match.SubStage,
match.HTeam,
HTeamCode = team1.TeamCode,
match.HGoal,
match.GGoal,
match.GTeam,
GTeamCode = team2.TeamCode,
match.WinNote,
match.Stadium,
match.Referee,
match.Visistors
});
return (IEnumerable<MatchesDetail>)await matchDetailList.ToListAsync();
}
Full code have been upload to Github at https://github.com/nguyentuananh921/Betting.git.
for more detail.
Thanks for your help.
I am so confuse about model in clean architech when i have more entities and the model I want to view in the WebUI contain many entities in domain.
Thanks for your help.
I have Modify public IEnumerable GetMatchDetailAsync() like that.
public IEnumerable<MatchesDetail> GetMatchDetailAsync()
{
#region TryOther way
var matchQuery = (from match in _context.Matches
join team1 in _context.Teams on match.HTeam equals team1.TeamName
join team2 in _context.Teams on match.GTeam equals team2.TeamName
join season in _context.Seasons on match.SeasonId equals season.SeasonId
select new
{
#region selectResult
//Remove to clear Select what I want to get.
#endregion
});
MatchesDetail matchesDetail = new MatchesDetail();
List<MatchesDetail> retList = new List<MatchesDetail>();
//IEnumerable<MatchesDetail> retList;
foreach (var item in matchQuery)
{
#region ManualMapping
matchesDetail.MatchId = item.MatchId;
//other field mapping
#endregion
retList.Add(matchesDetail);
}
#endregion
return retList;
}
And it work

Checking grandchildren records to return grand-parent. Linq

I have different roles and each user can have multiple roles. Each role is connected to customer record in different way, e.g. a business analyst has many-to-many relation to project and each customer has many projects; whereas a customer record can have only one project manager associated to it.
public class Customer
{
public CustomerProjectManager ProjectManager { get; set; }
public ICollection<Project> Projects{ get; set; }
...
}
public class Project
{
public ICollection<ProjectBusinessAnalyst> BusinessAnalysts { get; set; }
public ICollection<ProjectDeveloper> ProjectDevelopers { get; set; }
...
}
public class ProjectDeveloper
{
public int Id { get; set; }
public Project Project{ get; set; }
public int ProjectId { get; set; }
public string DeveloperId { get; set; }
public string DeveloperEmail { get; set; }
public string DeveloperName { get; set; }
}
public class CustomerProjectManager
{
public int Id { get; set; }
public ICollection<Customer> Customers { get; set; }
public string ProjectManagerId { get; set; }
public string ProjectManagerEmail { get; set; }
public string ProjectManagerName { get; set; }
public CustomerProjectManager()
{
Customers = new List<Customer>();
}
}
I need to fetch customer records on basis of roles. To explain further, I need to combine multiple customer lists fetched on the basis of different roles assigned to a single user. I am unable to form right linq query.
I have a sample query, mentioned below, which sometimes returns the right records but if I have a new user and no customers are assigned to this user, the query returns all existing customers. Its important for me that all the combination and filtration is done in Iqueryable
Please help!
public async Task<List<Customer>> FetchCustomers(string userId, List<string> userRoles, string userEmail)
{
if (userRoles.Contains("Admin"))
{
customer = _context.Customers;
}
else if (userRoles.Contains("Project Manager") ||
userRoles.Contains("Business Analyst") ||
userRoles.Contains("Developer"))
{
if (userRoles.Contains("Project Manager"))
{
customers = customers.Where(c => c.ProjectManager.ProjectManagerId == userId
|| c.Projects.Any(op =>
op.ProjectsCompleted.Any(assignee =>
assignee.UserId == userId)));
}
if (userRoles.Contains("Business Analyst"))
{
var allPossibleCustomers = _context.Customers.Where(c =>
c.Projects.Any(op => op.BusinessAnalysts.Any(ba => ba.BusinessAnalystId == userId)));
customers = customers?.Union(allPossibleCustomers) ?? allPossibleCustomers;
}
if (userRoles.Contains(Roles.Developer.GetDescription()))
{
var allPossibleCustomers = _context.Customers.Where(c =>
c.Projects.Any(op => op.PREDevDevelopersAssigned.Any(ba => ba.DeveloperId == userId)));
customers = customers?.Union(allPossibleCustomers) ?? allPossibleCustomers;
}
}
var listData = await PagingList<Customer>.CreatePageAsync(customers, page, limit);
return listData;
}
Apparently I was trying to return the wrong list. The linq query is correct.

Retrieving information from derived child object collections using LINQ

I have been trying to get a list of all Workflows that have Offices contained in a certain List by Office Id. I can easily get all of the Workflows that have SingleWorkflowSteps because they have only one Office, but have been unable to understand how I would successfully get those contained in a MultiWorkflowStep. All workflow steps have either a SingleWorkflowStep or a MultiWorkflowStep that contains two or more SingleWorkflowSteps. At the time I designed this, it seemed like a logical way to do this but atlas my LINQ-fu is not as good as I thought it was. Can someone please point me in the right directions. Code listed below:
var OfficesToFind = new List<int> (new int[] { 1,3,5,7,9,10,11,12} );
public class Workflow
{
public Workflow()
{
WorkflowSteps = new List<WorkflowStepBase>();
}
public int Id { get; set; }
public virtual ICollection<WorkflowStepBase> WorkflowSteps { get; set; }
}
public abstract class WorkflowStepBase
{
public int Id { get; set; }
public int StatusId { get; set; }
public virtual Workflow Workflow { get; set; }
public virtual Status Status { get; set; }
}
public class MultiWorkflowStep : WorkflowStepBase
{
public MultiWorkflowStep()
{
ChildSteps = new List<SingleWorkflowStep>();
}
public virtual ICollection<SingleWorkflowStep> ChildSteps { get; set; }
}
public class SingleWorkflowStep : WorkflowStepBase
{
public int? ParentStepId { get; set; }
public int OfficeId { get; set; }
public virtual MultiWorkflowStep ParentStep { get; set; }
public virtual Office Office { get; set; }
}
public class Office
{
public int Id { get; set; }
public string Name { get; set; }
}
public class WorkflowService : IWorkflowService<Workflow>
{
private readonly IRepository<Workflow> _workflowService;
private readonly IRepository<SingleWorkflowStep> _singleStepService;
private readonly IRepository<MultiWorkflowStep> _multiStepService;
public WorkflowService(IUnitOfWork uow)
{
_workflowService = uow.GetRepository<Workflow>();
_singleStepService = uow.GetRepository<SingleWorkflowStep>();
_multiStepSercice = uow.GetRepository<MultiWorkflowStep>();
}
// ~ ------- Other CRUD methods here -------- ~
public IEnumerable<Workflow> GetWorkflowFilter(List<int> statuses, List<int> offices...)
{
var query = _workflowService.GetIQueryable(); // returns an IQueryable of dbset
if(statuses.Any())
{
query = query.Where(q => statuses.Contains(q.StatusId));
}
if(offices.Any())
{
// Get all active single steps and the ones that contain the offices
singleSteps = _singleStepService
.Where(s => s.StatusId == (int)Enumerations.StepStatus.ACTIVE)
.Where(s => offices.Contains(s.OfficeId));
// Get all of the parent Workflows for the singleSteps
var workflows = singleSteps.Select(w => w.Workflow);
// Update the query with the limited scope
query = query.Where(q => q.Workflow.Contains(q));
}
return query.ToList();
}
}
OK, after a good night sleep, being all bright-eyed and bushy-tailed, I figured out my own problem. First the updated code was all wrong. Because each derived WorkflowStep has access to the Workflow and each MultiWorkflowStep contains a list of SingleWorkflowSteps - when I get the list of all SingleWorkflowSteps (which would include all from MultiWorkflowStep(s)), I simply needed to get a list of all of the parent Workflows of the SingleWorkflowSteps. Next I updated my query to limit the Workflows that were contained in the new Workflow list and here is the correct code for the GetWorkflowFilter method:
...
if(offices.Any())
{
// Get all active single steps and the ones that contain the offices
singleSteps = _singleStepService.Where(s => s.StatusId == (int)Enumerations.StepStatus.ACTIVE).Where(s => offices.Contains(s.OfficeId));
// Get all of the parent Workflows for the singleSteps
var workflows = singleSteps.Select(w => w.Workflow);
// Update the query with the limited scope
query = query.Where(q => q.Workflow.Contains(q));
}
return query.ToList();
}

Clearing children deletes parent

I have three related tables. Calendar 1...* CalendarUser *...1 User. When I have edited the CalendarUsers in the edit calendar view I then post the ViewModel back to the controller. Here is my controller code:
[HttpPost]
public ActionResult Edit(int id, CreateCalendarViewModel cvm)
{
long userId = long.Parse(User.Identity.Name);
db.Calendars.Attach(cvm.CurrentCalendar);
cvm.Users= DbExtensions.GetUserList(userId);
if (ModelState.IsValid)
{
////Remove the deselected users
cvm.CurrentCalendar.CalendarUsers.Clear();
//Get the names from the selected users
var selectedUsers = from u in cvm.Users
where cvm.SelectedUsers.Contains(u.Key)
select new KeyValuePair<long, string>(long.Parse(u.Key), u.Value);
foreach (var selectedUser in selectedUsers)
{
User user = db.Users.Find(selectedUser.Key);
//If usr does not exist create a new
if (user == null)
{
db.Users.Add(new User
{
UserId = selectedUser.Key,
Name = selectedUser.Value,
Expires = DateTime.Now,
AccessToken = string.Empty
});
}
//Add the binding to the calendar
cvm.CurrentCalendar.CalendarUsers.Add(new CalendarUser
{
CalendarId = cvm.CurrentCalendar.CalendarId,
UserId = selectedUser.Key
});
}
db.Entry(cvm.CurrentCalendar).State = EntityState.Modified;
db.SaveChanges();
}
return View(cvm);
}
Here are my classes:
public partial class Calendar
{
public Calendar()
{
this.CalendarUsers = new HashSet<CalendarUser>();
}
public int CalendarId { get; set; }
public string CalendarTitle { get; set; }
public string CalendarDescription { get; set; }
public long UserId { get; set; }
public virtual User User { get; set; }
public virtual ICollection<CalendarUser> CalendarUsers { get; set; }
}
public partial class CalendarUser
{
public int CalendarUserId { get; set; }
public int CalendarId { get; set; }
public long UserId { get; set; }
public Nullable<bool> IsAdmin { get; set; }
public virtual Calendar Calendar { get; set; }
public virtual User User { get; set; }
}
public partial class User
{
public User()
{
this.Calendars = new HashSet<Calendar>();
this.CalendarUsers = new HashSet<CalendarUser>();
}
public long UserId { get; set; }
public string Name { get; set; }
public virtual ICollection<Calendar> Calendars { get; set; }
public virtual ICollection<CalendarUser> CalendarUsers { get; set; }
}
For some reason when i save the changes the calendar is being deleted as well? I've searched a bit but noone seem to have the same problem? Am I doing it wrong? Is there a better way to update/remove related entities?
It seems that I forgot to include a hidden field in in the view containing the id of the user and the result was that when I updated the calendar it saved with Id = 0 and thus hid the objects in the view for the specified user. Mental note: Always verify in the database what is really happening.
I also need to look into whats happening when I send objects back and forth between views and controller. Sometimes it seems to manage by itself and sometimes I need to specify all the fields myself.

Multiple Parent models for a child model

I'm creating an MVC3 asp.net application using Entity Framework 4 and C#.
I've tried to read up on EF and model binding, lazy loading, etc. But I've hit an obstacle.
I have a User Model. The Store and UserType models can have an ICollection of Users. When I add a User with the Create Action, How do I specify multiple parents?
I think that I only know how to add if there is one parent.
My Models:
public class UserType
{
public virtual int ID { get; set; }
public virtual string UserTypeName { get; set; }
public virtual ICollection<User> Users { get; set; }
}
public class Store
{
public virtual int ID { get; set; }
public virtual string StoreName { get; set; }
public virtual Address StoreAddress { get; set; }
public virtual ICollection<Workroom> Workrooms { get; set;}
public virtual ICollection<User> Users { get; set; }
}
public class User
{
public virtual int ID { get; set; }
public virtual string Username { get; set; }
public virtual string Email { get; set; }
public virtual Store Store { get; set; }
public virtual UserType UserType { get; set; }
}
Here is my db context:
public DbSet<Workroom> Workrooms { get; set; }
public DbSet<Ticket> Tickets { get; set; }
public DbSet<Customer> Customers { get; set; }
public DbSet<Store> Stores { get; set; }
public DbSet<User> Users { get; set; }
public DbSet<UserType> UserTypes { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Store>()
.HasMany(store => store.Workrooms)
.WithRequired(workroom => workroom.Store);
modelBuilder.Entity<Store>()
.HasMany(store => store.Users)
.WithRequired(user => user.Store);
modelBuilder.Entity<UserType>()
.HasMany(usertype => usertype.Users)
.WithRequired(user => user.UserType);
base.OnModelCreating(modelBuilder);
}
Here's my create action:
public ActionResult Create()
{
return View(new User());
}
//
// POST: /Users/Create
[HttpPost]
public ActionResult Create(User newUser)
{
try
{
int storeID = newUser.Store.ID;
var store = _db.Stores.Single(r => r.ID == storeID);
store.Users.Add(newUser);
_db.SaveChanges();
return RedirectToAction("Index");
}
catch (Exception ex)
{
ModelState.AddModelError("", ex.InnerException.Message);
return View();
}
}
Do I just add another "Add" call for UserType? for example:
int userTypeID = newUser.UserType.ID
var usertype = _db.UserTypes.Single(s => s.ID == userTypeID)
How would the Entity Framework know that Users has another Parent??? ...do I care?
My hunch is that I should be doing this a different way, more specific and more accurate.
In this case, you probably want to add the user to the Users table, rather than the Stores. Then you assign the StoreID and UserTypeID to the user before you commit.
It looks like you're already setting the StoreID in your UI, are you doing the same for UserType? If so, then just add the user to the users table and you should be good.

Resources