I'm having an issue with a site that I'm writing in C# ASP using Entity Framework for the database. One of the data models that I'm using to store and retrieve data called DowntimeEvent contains 2 Lists AffectedSystems and AffectedDepartments. While I'm running the application in Visual Studio those lists store and retrieve just fine. But if I stop and restart the application the DowntimeEvents are still stored in my database, however the Lists for Affected Departments, and Affected Systems are null when I try to retrieve them.
Here's the Model I'm using to store the data
public class DowntimeEventModel
{
[Key]
public int ID { get; set; }
[Required]
public DateTime StartDateTime { get; set; }
[Required]
public DateTime EndDateTime { get; set; }
public int LocationID { get; set; }
[Required]
public string Description { get; set; }
//public int DepartmentID { get; set; }
//public int SystemID { get; set; }
public virtual ICollection<int> AffectedSystems { get; set; }
public virtual ICollection<int> AffectedDepartments { get; set; }
//public virtual ICollection<SystemModel> AffectedSystems { get; set; }
//public virtual ICollection<DepartmentModel> AffectedDepartments { get; set; }
}
Here's an example Controller of how I'm saving the data, and by the way this seems to be working just fine in storing the lists.
[HttpPost]
public ActionResult DowntimeEvent(DowntimeEventModel downtimeEvent)
{
PowerteqContext.DowntimeEvents.Add(downtimeEvent);
PowerteqContext.SaveChanges();
return View(SetupDowntimeEventViewModel());
}
It was this method that tipped me off to there being an issue with data retrieval after trying to write this report and trying to figure out why AffectedSystems was sometimes null and sometimes not. In the inner foreach loop I tried to access the ListAffectedSystems directly just to see if the loop might not be null that way and it is after a restart, but it's not if I add them and don't restart.
public ActionResult ReportUptimeBySystems()
{
var EndTime = DateTime.Now;
var StartTime = DateTime.Now.AddDays(-28);
var uptimeHours = new TimeSpan(1);
if (EndTime != StartTime)
uptimeHours = EndTime - StartTime;
List<ReportUptimeBySystem> SysUps = new List<ReportUptimeBySystem>();
var DownTimes = PowerteqContext.DowntimeEvents.AsEnumerable();
var Systems = PowerteqContext.Systems.AsEnumerable();
foreach (var x in Systems)
{
ReportUptimeBySystem sys = new ReportUptimeBySystem();
sys.SystemTimeUP = uptimeHours;
sys.SystemName = x.SystemName;
foreach (var y in DownTimes)
{
if(PowerteqContext.DowntimeEvents.Find(y.ID).AffectedSystems.Contains(x.ID))
{
sys.SystemTimeUP -= y.StartDateTime - y.EndDateTime;
}
}
SysUps.Add(sys);
}
return View(SysUps);
}
Another developer suggested that the issue may be in my Entity Framework Configuration. But I don't know where to look to even try to fix that.
For reference the whole application can be found here. The database I'm using is Microsoft SQL Serverhere
Entity framework will only automatically load relationships if it finds properties representing collections of another entity. It also must be able to identify foreign keys. By standards SystemModel and DepartmentModel should have a property DowntimeEventID, otherwise you'll have to inform it how to do this for you.
You should also ensure that lazy loading isn't disabled.
https://msdn.microsoft.com/en-us/data/jj574232.aspx
Disable lazy loading by default in Entity Framework 4
Here is a good example from a related question.
Many-to-many mapping table
public class DowntimeEventModel
{
[Key]
public int ID { get; set; }
[Required]
public DateTime StartDateTime { get; set; }
[Required]
public DateTime EndDateTime { get; set; }
public int LocationID { get; set; }
[Required]
public string Description { get; set; }
public virtual ICollection<SystemModel> AffectedSystems { get; set; }
public virtual ICollection<DepartmentModel> AffectedDepartments { get; set; }
}
Assuming AffectedSystems and AffectedDepartments are also EF entities with which DowntimeEventModel is linked with foreign keys with, you could try to explictly included them when you fetch your DowntimeEventModel results as such:
PowerteqContext.DowntimeEventModel.Include("DowntimeEventModel.AffectedSystems").Include("DowntimeEventModel.AffectedDepartments").ToList();
Related
I want to update a List of Custom Objects stored in a class in entity Framework, But I'm running into this error: the entity type list`1 is not part of the model for the current context. I have observed what the problem is, but I don't have enough experience to solve this problem. Refer below code to get a better understanding of the issue at hand.
public class Appointment
{
public int AppointmentID { get; set; }
public int PetID { get; set; }
public int DoctorID { get; set; }
public DateTime AppointmentDate { get; set; }
public Status AppointmentStatus { get; set; }
public virtual List<ObservedPetIssue> ObservedPetIssueID { get; set; }
public string Reason { get; set; }
public virtual List<PrescribedMedicine> Prescription { get; set; }
public virtual List<DiagnosedSymptom> DiagnosedSymptomID { get; set; }
public virtual Vital VitalID { get; set; }
public virtual List<PrescribedTest> PrescribedTestID { get; set; }
public virtual List<Recommendation> RecommendationID { get; set; }
}
This is the class which has a list of other classes and one property which has a single class(Vital).
Here is the observation:
1)If I edit any field like PetID, DoctorID, or AppointmentStatus and write db.Entry(appt).CurrentValues.SetValues(editedAppointment); The changes are saved
If I edit any field inside VitalID and write db.Entry(appt.VitalID).CurrentValues.SetValues(editedAppointment.VitalID); The changes are saved
If I add any PrescribedMedicine to the Prescription list, or modify the existing PrescribedMedicine or not modify anything at all and write db.Entry(appt.PrescribedTestID).CurrentValues.SetValues(editedAppointment.PrescribedTestID); and error is throw stating: the entity type list`1 is not part of the model for the current context
I've Tried db.Entry(appt.Prescription).State = EntityState.Modified, still no success.
That you do is similar that db.Entry(new List<PrescribedTest>()). This fail because the db context don't know the entity type List<PrescribedTest>.
This work with VitalID because it's similar that db.Entry(new Vital()) and that success because the db context know the entity type Vital.
If you want update a full entity collection, you can :
context.Entry(appointment).Collection(a => a.PrescribedTestID).CurrentValue = editedAppointment.PrescribedTestID;
Department and store model. They are a one to one relationship. when I do the (Include) only some models it brings me the complete data.
The data is correctly in the database
var orders = await _context.Order.Include(o => o.Departament)
.Include(o => o.Store).ToArrayAsync();
Model Order
public class Order
{ [Key]
public string Order_Id { get; set; }
[DataType(DataType.Date)]
public DateTime Date { get; set; }
public string Number_Order { get; set; }
public int Qty { get; set; }
[DataType(DataType.DateTime)]
public DateTime Imported { get; set; }
[DataType(DataType.DateTime)]
public DateTime Modified { get; set; }
[DataType(DataType.DateTime)]
public DateTime Exported { get; set; }
public bool IsActive { get; set; }
[ForeignKey("Departament")]
public string DepartmentId { get; set; }
[ForeignKey("Store")]
public string StoreId { get; set; }
public virtual ICollection<OrderDetail> OrderDetails { get; set; }
public Departament Departament { get; set; }
public Store Store { get; set; }
}
.
I just need to solve that problem of getting the data correctly.
what do u mean one to one!!! i think your design is one to many.
as Steve Py said in his comment ## The relationship between Order->Department and Order->Store is not One-to-One, it is Many-to-One. (Many orders could refer to the same Department) ##
use virtual keyword for navigation properties.
accroding to https://stackoverflow.com/a/41881299/18399373
you can use virtual keyword to load related data in lazy way
use explicit loading and check it.
Entity Framework supports three ways to load related data - eager loading, lazy loading and explicit loading
I have a Model Rental in my ASP.Net 4.5 MVC Project. Rental has 2 foreign keys ProfileId(Profile Model) & ItemId(Item Model). Both are set properly when the Rental record is created.
In Controller #1 if i run:
var rentals = GetRentals(6);
public IQueryable<Rental> GetRentals(int parent)
{
return db.Rentals.Where(t => t.ProfileId.Equals(parent));
}
var rentalArray = rentals.ToArray();
rentalArray has the proper item id and FK index, allowing me to run rentalArray[i].Item.Name Good Response Pic from Code Above
Now In controller #2 if i run
var rentals = GetRentals(6);
public IQueryable<Rental> GetRentals(int parent)
{
return db.Rentals.Where(t => t.ProfileId.Equals(parent));
}
var rentalArray = rentals.ToArray();
In this query i loose the item FK property of the Rental, though the ItemId is still coming in properly. I am unable to run rentalArray[i].Item.Name as Item is null.
Both are the same database record, Im just querying in a different Controller/Method. Picture of bad response
I cannot determine why Rental.Item property comes in null on the second query? Database Diagram
Rental Model:
public class Rental
{
public int RentalId { get; set; }
public int ItemId { get; set; }
[IgnoreDataMember]
public virtual Item Item { get; set; }
public int ProfileId { get; set; }
[IgnoreDataMember]
public virtual Profile Profile { get; set; }
public DateTime RequestDate { get; set; }
public bool? Accepted { get; set; }
public bool? Complete { get; set; }
public DateTime BeginRental { get; set; }
public DateTime EndRental { get; set; }
public int ChargeAmount { get; set; }
public bool Canceled { get; set; }
public string ChargeId { get; set; }
}
You can use include method
using System.Data.Entity;
and you can use it like this:-
return db.Rentals.include(tt => tt.Profile).include(ttt => ttt.Item).Where(t => t.ProfileId.Equals(parent));
Thanks to bash.d for finding issue.
Have you noticed that in your bad picture you have
LibLob.Models.Profile instead of a reference to an System.Data.Entity
object? You said your DBContext was the same?
Controller #1 was using a ApplicationDBContext while controller#2 was using ProxylessApplicationDbContext, resulting in Rental.Item appearing but being null in controller #2. Fixed by adding a second dbcontext and using that only for method to retrieve rentals.
I have an application that is written on the top of ASP.NET MVC 5 framework along with Entity 6 Framework. I am using Database-first approach instead on code-first approach.
I am aware on how to build simple relation between my models using virtual navigations like public virtual RelationModel Relation { get; set } or public virtual ICollection<RelationModel> Relations { get; set }
However, the requirement is more tricky this time. I need to be able to build a relation using composite key not just a single column. I want to add a relation where the joiner/join-clause on one side should be a computed property called LocalDate and DateOf on the other side AND OwnerId column == UserId of the other side.
Here is an example of my models
My parent model looks like the following
public Entry
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
[ForeignKey("Owner")]
public int OwenerId { get; set; }
public DateTime StartedAt { get; set; }
public int UtcOffset { get; set; }
public virtual User Owner { get; set; }
// This puts the StartedAt in the correct date state which is needed for the relation
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime LocalDate
{
get
{
return StartedAt.AddSeconds(UtcOffset * -1).Date;
}
}
// This is the relation that needs a complex join clause
public virtual ICollection<Bucket> Buckets { get; set }
}
Here is my child model looks like the following
public Bucket
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public int UserId { get; set; }
public DateTime DateOf { get; set; } //This is a date it or stored with 00:00:00.000 time in the database
public virtual User Owner { get; set; }
}
From my Entry model, I want to be able to access my Buckets relations using the following logic Entry.LocalDate == Bucket.DateOf && Entry.UserId == Bucket.UserId
Note that the LocalDate property is NOT a database column, rather a computed property
Is it possible to construct this kind of relation between my model where I can use .Include(x => x.Buckets) to get the relations accordingly? If so, how? If it is not possible, what are other ideas that can be used to deliver the same results?
I think I have read every article and stack overflow question regarding this, but cannot work out the solution. Let me start out with my models
public class Entry
{
public Entry ()
{
DateEntered = DateTime.Now;
}
public int Id { get; set; }
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
[Required]
public string Email { get; set; }
public string Number { get; set; }
public string FbId { get; set; }
[ReadOnly(true)]
public DateTime DateEntered { get; set; }
public string AccessToken { get; set; }
//Relationsips
public Backgrounds Background { get; set; }
public Cars Car { get; set; }
}
public class Backgrounds
{
public int Id { get; set; }
public string Name { get; set; }
public string Filename { get; set; }
}
public class Cars
{
public int Id { get; set; }
public string Name { get; set; }
public string FileName { get; set; }
}
Now in my controller, I am updating the entry. Like follows
// PUT /api/entries/5
public HttpResponseMessage Put(Entry entry)
{
if(ModelState.IsValid)
{
_db.Entries.Attach(entry);
_db.Entry(entry).State = EntityState.Modified;
_db.SaveChanges();
return new HttpResponseMessage(HttpStatusCode.NoContent);
}
throw new HttpResponseException(HttpStatusCode.BadRequest);
}
My Entry model gets updated correctly, but if for eg entry.Background.Name changes, this will not be persisted to the database. My controller is accepting the entire entry model including its relationships => Backgrounds and Cars. However any value that is changed to the relationship is not updated or reflected. Any elegant solution without having to query the database then updating? I dont want to have any extra queries or lookups before I update.
Thanks
Tyrone
You must manually tell EF about all changes done to the object graph. You told EF just about change to entry instance but you didn't tell it about any change to related entities or relations itself. There is no elegant way to solve this. You have generally two options:
You will use some DTOs instead your entities and these DTOs will have some flag like IsDirty - when you receive object graph back to your controller you will reconstruct entities from DTOs and set their state based on IsDirty. This solution needs further extensions for example if your client can also delete relations.
You will query object graph from database and merge your incoming changes to entities retrieved from database.
There are some partial solutions like forcing to save changes to all related objects by setting their state to modified and identifying new objects by Id == 0 but again these solutions work only in specific scenarios.
More complex discussion about this problem.