Reformat shown data - asp.net

What's the easiest way to reformat data shown in the second view ?
I use .Net in the backend and Angular in the frontend.
I have a method that returns collection of attendances that has a collection of users with their statuses, and I can filter them to only query data in a date range.
I have no idea how to get the same data to get shown by users, since database structure is as follows:
Training has many schedules.
Schedules have Many Attendances.
Attendances have many Attendants and every Attendant has his status.
Now its easy to show data by attendances, but its impossible for me to figure out how to show data by attendants(users) to show all their attendances.
Is there any example someone could provide on something similar and how to do it in Asp, or angular.
I have tried creating new dto models, but I cant get neccessary data without using many queries, and mapping data too many times.
I have searched similar questions but didn't find anything relevant.
EDIT:
I am looking for the simplest solution.
I would like to know how to solve this both ways, and I can't decide which way is better ?
Here is the current method, which works for the first view:
public ICollection<AttendanceModel> ScheduleLog(int scheduleId, SearchAttendancesModel searchAttendances)
{
if (searchAttendances == null)
throw new ArgumentNullException("searchAttendances");
if (searchAttendances.Attendants == null)
throw new ArgumentNullException("searchAttendances.Attendants");
if (searchAttendances.AttendantStatuses == null)
throw new ArgumentNullException("searchAttendances.AttendantStatuses");
var query = _context
.Attendances
.Where(x=>x.ScheduleId==scheduleId)
.AsQueryable();
if (searchAttendances.FromDate != DateTime.MinValue)
{
query = query.
Where(x => x.Date >= searchAttendances.FromDate);
}
if (searchAttendances.ToDate != DateTime.MinValue)
{
query = query.
Where(x => x.Date <= searchAttendances.ToDate);
}
return query.ToList().Select(x => x.MapToAttendanceModel()).ToList();
}
It gets me the neccesary data to show for the first view, which I can easily show with tables thoru ng-repeat, but as I already said, I have many difficulties grouping data by user instead of by schedule, and then showing that data(all attendances per user) instead of all users per attendance.
Here is how my models look like:
This is schedule that has all the attendances:
public class ScheduleModel
{
public int Id { get; set; }
[Required]
public DateTime StartDate { get; set; }
[Required]
public DateTime EndDate { get; set; }
public string Description { get; set; }
public virtual ICollection<AttendanceModel> Attendances { get; set; }
}
This is attendance that has date for attendance and collection of attendants each of which have user and their status.
public class AttendanceModel
{
public int Id { get; set; }
[Required]
public DateTime Date { get; set; }
[Required]
public virtual ICollection<AttendantModel> Attendants { get; set; }
}
This is one Attendant that has user and status for that attendance
public class AttendantModel
{
public int Id { get; set; }
public virtual LookupModel ApplicantStatus { get; set; }
public virtual UserModel User { get; set; }
}

Related

ASP.NET MVC Auto generate integer number

Good day, a really newbie developer here.
I Have a form and it have a entity of "QueueNumber" Can someone show me how to code so that when ever i save my form it generates automatically QueueNumber + the Prefix, btw my prefix entity is in another class
public class Queue
{
public int QueueId { get; set; }
[Required]
public string Name { get; set; }
public string QueueNumber
public int ServiceId { get; set; }
public Service Service { get; set; }
}
-
public class Service
{
public int ServiceId { get; set; }
[Display(Name = "Service Name")]
public string ServiceName { get; set; }
[Display(Name = "Service Letter")]
public string ServiceLetter { get; set; }
[Display(Name = "Status")]
public bool? Status { get; set; }
[Display(Name = "Assigned Location")]
public int? LocationId { get; set; }
public virtual Location Location { get; set; }
public virtual ICollection<Customer> Customer { get; set; }
}
Outcome in database :
1. A001
2. A002
3. A003
i just want to be able to generate a queue number automatically and when i save in data base its like A= Service Letter and 001=QueueNumber. Thankyou
If the QueueNumber needs to be persisted to the table, then I would set it up as a calculated column so that the database can manage computing it and updating it if the underlying fields change.
If it is just something that you want to represent in the UI then I would recommend having the view model calculate this.
The entity can calculate something like this with a [NotMapped] attribute. For example:
public class Queue
{
public int QueueId { get; set; }
[Required]
public string Name { get; set; }
[NotMapped]
public string QueueNumber
{
get { return string.Format("{0}{1:000}", Service?.ServiceLetter ?? "?", QueueId);
}
[ForeignKey("Service")]
public int ServiceId { get; set; }
public Service Service { get; set; }
}
The problem with this approach is that to be able to rely on your Queue to reveal a QueueNumber, the Queue must eager load the Service, or you enable lazy loading and risk that performance hit vs. having Service == #null and getting an exception or invalid QueueNumber result. In the above example, if the Service isn't eager loaded you will get back something like "?001".
I prefer to use ViewModels for a number of reasons including performance, security, and handling conditions like this more cleanly.
For example, given a QueueViewModel as such:
[Serializable]
public sealed class QueueViewModel
{
public int QueueId{ get; set; }
public string Name { get; set; }
public string ServiceName { get; set; }
public string ServiceLetter { get; set; }
public string QueueNumber
{
return string.Format("{0}{1:000}", ServiceLetter, QueueId);
}
}
Then when reading the data, we don't pass Entities to the view, we pass our view model...
var viewModel = context.Queues
.Where(x => x.QueueId == queueId)
.Select(x => new QueueViewModel
{
QueueId = x.QueueId,
Name = x.Name,
ServiceName = x.Service.Name,
ServiceLetter = x.Service.ServiceLetter
}).Single();
return viewModel;
The benefits of this approach:
We don't have to worry about eager/lazy loading. The query fetches everything needed, and our view model can compute anything needed from the data loaded. (Queries can compute values as well if you like, but be wary of limitations in that the query has to be able to go to SQL, so no user functions, etc.)
Performance is improved since the query only returns the data needed rather than entire entity graphs, and no rish of lazy load hits.
Security is improved, we expose no more data to the client than is expected/needed, and we don't open the door for "lazy" updates where entities are attached to a context and saved without proper validation.

Display results from multiple sources in ASP.NET

Okay, so I'm in the middle of an ASP.NET project in work at the minute and it's all going well. So far I have all the models, views and controllers made and they all work perfectly, but now I have been told that I need to make a class (lets just call it results to make life easy here) to display all the data. This is an example I was given for what the displayed results would look like:
There are multiple different displays at the moment for different things like a person, travel insurance, car insurance etc. and the only common things between each different display are the full name, contact email, contact number, contact address and recorded time stamp. It's the additional data that changes for each display depending on what is being requested, i.e., person displays all the information stored about the person like full name, age, DOB, mobile number, home address and so on while travel insurance displays all information stored about the travel insurance for the person who is asking like the trip type, trip destination, group type (single/couple/family/friends), travelers ages and so on..
My question is this: how do I create this results class to display the required data? Do I need another controller, model and view or do I just need to create a class called Result and put everything into that? (I think I just have to create a class but I am not sure, hence why I am asking) Also, how do I make it in such a way that different things are displayed in the additional data depending on what the person searched for? Like I don't need all the additional data about car insurance appearing when a person searched their travel insurance - does this mean I will need multiple forms of the results class which all refer to a different searchable thing or can everything go in the one class?
Apologies if this is awfully worded and/or a bad question - I did try looking for something to help myself before posting here but I couldn't find anything. I'm also quite new to the whole ASP.NET front so apologies if I'm missing anything obvious.
Create a base Model class and put all the common properties to be displayed in that, and derive other Model classes from that class with their specific properties in them. You can pass Person object to the view where Person's info need to be displayed and TravelInsurance object where Travel Insurance's info needs to be displayed.
public class ModelBase
{
public string FullName { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
public string Address { get; set; }
public DateTime TimeStamp { get; set; }
}
public class Person : ModelBase
{
public string DateOfBirth { get; set; }
public string MobileNumber { get; set; }
}
public class TravelInsurance : ModelBase
{
public string TripType { get; set; }
public string TripDestination { get; set; }
}
If that does not sound like the way to go, you can have a generic Model class with a generic Data property within it:
public class Model<T>
{
public string FullName { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
public string Address { get; set; }
public DateTime TimeStamp { get; set; }
public T Data { get; set; }
}
public class Person
{
public string DateOfBirth { get; set; }
public string MobileNumber { get; set; }
}
public class TravelInsurance
{
public string TripType { get; set; }
public string TripDestination { get; set; }
}
where you can pass objects to your view like this:
var x = new Model<Person> { FullName = "...", Data = new Person { } };
OR
var x = new Model<TravelInsurance> { FullName = "...", Data = new TravelInsurance { } };

EF Core - Identity field suddenly jumped by 1000 and not able to search with Id

I am having a problem with primary key/Id of one table in a project.
In this table, the Id suddenly jumped from 38 to 1039.
Now the real issue is, when i find the entity by 1039 it doesn't exists but finding it by 39 gives me the entity.
I am not sure about this behaviour and hence not able to find the solution.
My model
public class Domain : Entity
{
public string Name { get; set; }
public string Description { get; set; }
}
public abstract class Entity
{
public int Id { get; set; }
public DateTime InsertDate { get; set; }
public DateTime? UpdateDate { get; set; }
public DateTime? DeleteDate { get; set; }
public bool IsDeleted { get; set; }
}
Method is like this...
public async Task<Response> Delete(int id)
{
var domain = await DataContext.Domains.FindAsync(id);
if (domain == null)
{
return new Response(ResponseType.NotFound);
}
}
Can anyone please help ?
it depend from Database setting IDENTITY-CACHE.
Identity cache store some values of a identity columns in case of SQL CRASH during a transaction or similar.
To avoid gaps in an identity column, you need to set IDENTITY-CACHE to OFF running this command on a SQL query window:
ALTER DATABASE SCOPED CONFIGURATION SET IDENTITY_CACHE = OFF
GO
you will find more informations here:
https://social.technet.microsoft.com/wiki/contents/articles/40666.sql-server-2017-identity-cache-feature.aspx

Check value prior to form submit in POST controller

Sorry if the subject is inaccurate, but basically upon submit of a Form I want to compare the previous value of the model's Foreign Key.
My model is:
public class Booking
{
public int ID { get; set; }
[ForeignKey("Store")]
public int StoreID { get; set; }
public virtual Store Store { get; set; }
public string BookedBy { get; set; }
public DateTime? DateBooked { get; set; }
public string Description { get; set; }
public DateTime FromDate { get; set; }
public DateTime ToDate { get; set; }
public string Status { get; set; }
}
After editing a booking in Edit view and submitting, I want to check if the StoreID has been modified, so that I can perform a required action.
I was creating an instance of Booking as oldBooking and then comparing StoreID with booking.StoreID passed back from View, but this created an Attach error when I saved the Edited form.
Any suggestions?
Edited 27/1/15:
public ActionResult Edit([Bind(Include = "ID,StoreID,BookedBy,DateBooked,Agreement,Description,FromDate,ToDate")] Booking booking, string returnURL)
{
if (ModelState.IsValid)
{
Booking oldBooking = db.Bookings.Find(booking.ID);
int prevStoreID = oldBooking.StoreID;
db.Entry(booking).State = EntityState.Modified;
db.SaveChanges();
if(prevStoreID == booking.StoreID)
{
sendStoreChangeEmail(prevStoreID, booking.StoreID);
}
return RedirectToAction("Index", "Home", null);
}
ViewBag.StoreID = new SelectList(db.Stores, "ID", "ID", booking.StoreID);
return View(booking);
}
When attempt to update db entry state I get this error:
"Attaching an entity of type 'uatlab2.Models.Booking' failed because another entity of the same type already has the same primary key value. This can happen when using the 'Attach' method or setting the state of an entity to 'Unchanged' or 'Modified' if any entities in the graph have conflicting key values. This may be because some entities are new and have not yet received database-generated key values. In this case use the 'Add' method or the 'Added' entity state to track the graph and then set the state of non-new entities to 'Unchanged' or 'Modified' as appropriate."
After reading a couple of other posts and googling 'detach', i read this article:
ASP MVC How to update DB entry with collections field
and after I have got prevStoreID do this:
((IObjectContextAdapter)db).ObjectContext.Detach(oldBooking);
And it works.
Thanks for your help and inspiration.
C

Selecting records from parent table depending on child table filter

This should be simple, but I'm getting confused.
I have a parent/child tables - and all I want to do, is select from the parent table, depending on filtering of the child table.
So the parent table, Rooms, is linked one to many to the clients table - I want to select rooms, where there are no linked records in the Clients table, where the clients.Departure date is before a specific date:
public class Room
{
public int RoomId { get; set; }
public string RoomName { get; set; }
public List<Client> Clients { get; set; }
}
public class Client
{
public int ClientId { get; set; }
public int RoomId { get; set; }
public string Name { get; set; }
public DateTime Arrival { get; set; }
public DateTime Departure { get; set; }
public Room Room { get; set; }
}
In my controller I have been trying:
public ActionResult Avail()
{
DateTime dteFrom = DateTime.Parse("2012-07-01"); //hard coded for testing
Room room = db.Rooms.Where(r => r.Clients.Any(c => c.Departure <= dteFrom));
But I get the error message:
Cannot implicitly convert type 'System.Linq.IQueryable<ttp.Models.Room>' to 'ttp.Models.Room'. An explicit conversion exists (are you missing a cast?)
Can anyone suggest do I need to change my model classes, or my Where statement?
Room room represents a single room whereas db.Rooms.Where(r => r.Clients.Any(c => c.Departure <= dteFrom)) returns a list of rooms.
If you expect your query will only return one result, you could do the following:
Room room = db.Rooms.SingleOrDefault(r => r.Clients.Any(c => c.Departure <= dteFrom));
Or if you would like to return all the rooms that match the query, you could do the following:
IQueryable<Room> rooms = db.Rooms.Where(r => r.Clients.Any(c => c.Departure <= dteFrom));

Resources