LINQ JOIN Child Collection - linq

I have a meetingRepository class that returns IEnumerable and an attendeeRepository class that returns IEnumerable<Attendee>
public class meetingRepository
{
IEnumerable<Meeting> GetAll()
{
//return all Meetings
}
}
public class attendeeRepository
{
IEnumerable<Attendee>GetAll()
{
//return all Attendees
}
}
public class Meeting
{
public int Id { get; set; }
public DateTime Date { get; set; }
public string FilePath { get; set; }
public int Duration { get; set; }
public IEnumerable<Attendee> Attendees { get; set; }
}
public class Attendee
{
public int Id { get; set; }
public int MeetingId { get; set; }
public string Name { get set;}
public string Role { get; set; }
}
Im struggling to come up with the link statement that will join my IEnumerable<Meeting> object with my IEnumerable<Attendee> joining each Attendee in the Attendees property of the Meeting to its related Attendee object based on the Attendee.Id
Help appreciated
Edit
#Thomas the meetingRepository I have available does not load the Attendees, it is just a full list of all Meetings (I editted to include the Id property).
So, to clarify, my meetingRepository returns an IEnumerable of a partial Meeting object (no attendees)
Id
Date
Duration
FilePath
and my attendeeRepository returns an IEnumerable of participants (editted to include MeetingId
Id
MeetingId
Name
Role
Edit
I came up with the folowing that seems to work fine
var meetingsFull = from m in meetings
join a in attendees
on m.Id equals a.MeetingId into ma
select new Meeting
{
Id=pc.Id,
Date=pc.Date,
Duration=pc.Duration,
FilePath=pc.FilePath,
Attendees=ma
};

var attendees = attendeeRepository.GetAll();
foreach(var meeting in meetingRepository.GetAll())
{
meeting.Attendees = attendees.Where(at=>at.MeetingId == meeting.Id);
}
This should do it. After these assignments your all meetings now have the attendees lists ready in them.

Related

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.

I want to return Count of a Collection in addition to the other elements of a table in the database

I want to also return in addition to the parameters of the Buyers Class I want to return the number of properties owned by the buyer using a GET method in the controller.
How can I change the GET function to select the fullName, Credit and Number of Apartments owned:
public class Buyer
{
[Key]
public int ID { get; set; }
public string FullName { get; set; }
public int Credit { get; set; }
public ICollection<Apartment> apartments { get; set; }
}
// GET: api/Buyers
[HttpGet]
public IEnumerable<Buyer> GetBuyers()
{
return _context.Buyers
.Include(a => a.apartments);
}

Unable to get Item from SQLite.Net Async PCL

I am struggling to get an Item by ID using the asynchronous API of SQLite.Net Async PCL. Here is my model class
public class Invoice : IEntityBase
{
public Invoice()
{
LineItems = new List<LineItem>();
DateCreated = DateTime.Now;
}
[PrimaryKey, AutoIncrement, Column("_id")]
public int Id { get; set; }
public DateTime DateCreated { get; set; }
public int Term { get; set; }
public bool Paid { get; set; }
public decimal Total { get; set; }
public string Notes { get; set; }
[OneToMany(CascadeOperations = CascadeOperation.All)]
public List<LineItem> LineItems { get; set; }
}
And the LineItems that has a One to Many relationship here
[PrimaryKey, AutoIncrement, Column("_id")]
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public decimal Price { get; set; }
public string Category { get; set; }
public int Qty { get; set; }
[ForeignKey(typeof(Invoice))]
public int InvoiceId { get; set; }
[ManyToOne]
public Invoice Invoice { get; set; }
Here is the constructor:
public SQLiteAsyncConnection DbConnection;
public InvoiceDatabase(ISQLitePlatform platform, string databasePath)
{
if (DbConnection == null)
{
var connectionAsync = new Func<SQLiteConnectionWithLock>(() =>
new SQLiteConnectionWithLock
(
platform,
new SQLiteConnectionString(databasePath, false)
)
);
DbConnection = new SQLiteAsyncConnection(connectionAsync);
DbConnection.CreateTableAsync<Invoice>();
DbConnection.CreateTableAsync<LineItem>();
}
}
Other CRUD methods (Insert, GetALL) is working except getting an Invoice by ID, and both Visual Studio and Xamarin Studio are not giving me any useful stacktrace.
Here is the Get Method
private readonly InvoiceDatabase _database;
public InvoiceRepository(ISQLitePlatform platform, string databasePath)
{
if (_database == null)
{
_database = new InvoiceDatabase(platform, databasePath);
}
}
public async Task<Invoice> GetInvoice(int id)
{
var result = await _database.DbConnection.Table<Invoice>()
.Where(t => t.Id == id)
.FirstOrDefaultAsync();
return result;
}
I am passing in the Android implementation of SQLite, and like I said the Database is created but I am unable to get the Invoice object back, I even tried
public Task<Invoice> GetInvoiceWithChildren(int id)
{
return _database.DbConnection.GetWithChildrenAsync<Invoice>(id);
}
Any Help will be greatly appreciated.
After three days of chasing shadows it turned out that it is just a very simple thing that is tripping me up. I am tying to save a List of objects like so
[OneToMany(CascadeOperations = CascadeOperation.All)]
public List<LineItem> LineItems { get; set; }
I missed the part of the documentation that repeats the fact that SQLite.Net is a lightweight ORM - that point could not be stressed enough so you will have to remove your full size ORM hats such EF. So after reading from the SQLite-Net Extension documentation which says
Text blobbed properties
Text-blobbed properties are serialized into a text property when saved and deserialized when loaded. This allows storing simple objects in the same table in a single column.
Text-blobbed properties have a small overhead of serializing and deserializing the objects and some limitations, but are the best way to store simple objects like List or Dictionary of basic types or simple relationships.
I change my proptery like so and everything is now working as expected. Off now to dealing with the nuances of Async and Await
[TextBlob("LineItemBlobbed")]
public List<LineItem> LineItems { get; set; }
public string LineItemBlobbed { get; set; }

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.

How to get Users who only have some specific department id, Linq

I have following two entities
public class User
{
public int UserId { get; set; }
public string UserName { get; set; }
public List<Department> Departments { get; set; }
}
public class Department
{
public int DepartmentId { get; set; }
public string DepartmentName { get; set; }
public List<User> Users { get; set; }
}
As you see, relationship between two objects is M:N.
I wanna get User who only have specific department ID, in this case, How to get users using Linq?
Thanks in advance
int requiredId = ...
var usersInReqdDept = Users.Where(u => u.Departments
.Any(d => d.DepartmentId == requiredId));
If the Departments list can be null, you will need a null-check in the Where clause.
If you want to search the Departments list instead,
int requiredId = ...
var usersInReqdDept = Departments.Single(d => d.DepartmentId == requiredId)
.Users;
Of course, this will throw an exception if such a department doesn't exist.

Resources