I've searched and nothing I've come across works for this problem. I have child entities that all have a date completed field. When the parent entity is updated, I want to delete any child entities that don't have a value for the date completed field. Here's the code.
public int Save(ImmunizationForm form)
{
_context.Entry(form).State = EntityState.Detached;
//only clear our incomplete immunizations
var incompleteImmunizations = _context.ImmunizationFormImmunization.Where(x =>
x.ImmunizationFormId == form.Id && !x.DateCompleted.HasValue);
if (incompleteImmunizations.Any())
{
foreach (var i in incompleteImmunizations){
//_context.Entry(i).State = EntityState.Deleted;
_context.ImmunizationFormImmunization.Remove(i);
}
_context.SaveChanges(); //errors here
}
.....
}
My suspicion was that because I'm passing in an ImmunizationForm entity that has an Id value (meaning I'm not adding a new parent but updating), I would need to set the State to EntityState.Detached because further in my code I actually grab the entity to update from the database. But, that doesn't seem to help. As you can see I've tried both setting the State of the incompleteImmunization object to delete or just try to remove it. Neither are working. I keep getting the same error message...
The operation failed: The relationship could not be changed because one or more of the foreign-key properties is non-nullable. When a change is made to a relationship, the related foreign-key property is set to a null value. If the foreign-key does not support null values, a new relationship must be defined, the foreign-key property must be assigned another non-null value, or the unrelated object must be deleted.
Parent class
public class ImmunizationForm
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public ImmunizationForm()
{
ImmunizationFormImmunizations = new HashSet<ImmunizationFormImmunization>();
}
public int Id { get; set; }
public string Name { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<ImmunizationFormImmunization> ImmunizationFormImmunizations { get; set; }
}
Child class
public class ImmunizationFormImmunization
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public ImmunizationFormImmunization()
{
}
public int Id { get; set; }
[ForeignKey("ImmunizationForm")]
public int ImmunizationFormId { get; set; }
public short ImmunizationTypeId { get; set; }
public byte? GroupId { get; set; }
public byte DocumentationRequirement { get; set; }
public DateTime? DateCompleted { get; set; }
public string RejectionReason { get; set; }
public DateTime? RejectedDate { get; set; }
[Column(TypeName = "numeric")]
public decimal? RejectedBy { get; set; }
public virtual ImmunizationForm ImmunizationForm { get; set; }
public virtual TypeImmunization TypeImmunization { get; set; }
}
Related
I am using code first and have several classes that have navigation properties between themselves.
Issue Class:
public class Issue
{
public Issue()
{
Complaints = new List<Complaint>();
SubIssues = new List<Issue>();
}
[Key,ForeignKey("Complaints")]
public int IssueID { get; set; }
public string Name { get; set; }
public bool IsSubCategory { get; set; }
public virtual Issue ParentIssue { get; set; }
public virtual ICollection<Issue> SubIssues { get; set; }
public virtual ICollection<Complaint> Complaints { get; set; }
}
The Complaint Class:
public class Complaint
{
public Complaint()
{
CreateDate = DateTime.Now;
}
public int ComplaintID { get; set; }
public DateTime CreateDate { get; set; }
[MaxLength(2000)]
public string Description { get; set; }
public bool IsClosed { get; set; }
[ForeignKey("IssueID")]
public virtual Issue Issue { get; set; }
public int IssueID { get; set; }
}
The Complaint class is working fine. Where I am running into difficulties is with the Issues class which references the same table for SubIssues and ParentIssue. The idea is that each Issue record with IsSubCategory == false can have 0 to many related Issue records as a collection of SubIssues and each Issue record with IsSubCategory == true will have a 1 to 1 relationship with an Issue record as ParentIssue.
Because of some DBA standards I also need to specify the naming of the Foreign key fields, i.e. ParentIssueID rather than the Issue_ParentIssueID (or whatever it auto gens)
I would prefer to do this with data annotations but could use the OnModelCreating process if need be.
How would I go about fixing the issue class so that the proper tables are created?
IssueID can't be both a primary and a foreign key to itself. You need a property (and field) ParentIssueId.
public int? ParentIssueID { get; set; }
The mapping, if using fluent mapping, should look like this:
modelBuilder.Entity<Issue>()
.HasMany(i => i.SubIssues)
.WithOptional(i => i.ParentIssue)
.HasForeignKey(i => i.ParentIssueID);
ParentIssueID is int? because it's an optional relationship.
I'm using ASP.NET Core and EF Core and I have the two following parent and child classes. Each gift card can have many transactions:
public class GiftCard
{
public int Id { get; set; }
public string BarCode { get; set; }
public DateTime PurchaseDate { get; set; }
public string Comments { get; set; }
public byte[] Timestamp { get; set; }
public List<Transaction.Transaction> Transactions { get; set; }
}
public class Transaction
{
public int Id { get; set; }
public DateTime TransactionDate { get; set; }
public decimal TransactionAmount { get; set; }
public TransactionType TransactionType { get; set; }
public byte[] Timestamp { get; set; }
public GiftCard.GiftCard GiftCard { get; set; }
}
Based on what I read, this is the way to do it, by having navigation property on the parent and reference navigation in child. When I add my migrations and update the database using the command line, everything seemed ok in the database except that the GiftCardId foreign key in the Transactions table is nullable. I want to make sure this is NOT NULL. Am I missing a Data Annotation attribute?
Put the following property on your Transaction entity, and it should be resolved.
public int GiftCardId { get; set; }
What is happening with your definition is that a shadow property is being created and EF's Change Tracker is maintaining the relationships.
See here.
The method is really simple and I don't see what am I missing...
public int SaveEvent(Data.Models.Event evnt)
{
db.Events.Add(evnt);
db.SaveChanges();
return evnt.EventId;
}
here is the object declaration:
public class Event
{
public int EventId { get; set; }
public string Name { get; set; }
public ICollection<EventTag> EventTags { get; set; }
}
The evnt object contains a property name EventTags that contains 6 new elements.
The evnt is inserted in the database but not the EventTag... any idea ? no error nothing. just the EventTag are not added...
public class EventDbContext : DbContext
{
public DbSet<Event> Events { get; set; }
public DbSet<EventTag> EventTags { get; set; }
public DbSet<Tag> Tags { get; set; }
}
Here is a screenshot of the value:
If the EventTags are not being added to the database you may need to manually specify the EntityState for each tag.
public int SaveEvent(Data.Models.Event evnt)
{
foreach(var tag in evnt.EventTags)
{
db.Entry(tag).State = EntityState.Added;
}
db.Events.Add(evnt);
db.SaveChanges();
return evnt.EventId;
}
You might also want to update your class definition and set the EventTags property as virtual.
public class Event
{
public int EventId { get; set; }
public string Name { get; set; }
public virtual ICollection<EventTag> EventTags { get; set; }
}
In your screenshot it looks like the tags are loading, but not the Location property on the tags. If that's the case, then make sure to set the Location property to virtual as well.
I have these method classes:
public class Links
{
[Key]
public int LID { get; set; }
public string Link { get; set; }
public string Type { get; set; }
public string Filename { get; set; }
public virtual int RessourceId { get; set; }
}
public class Ressource
{
[Key]
public int RessourceId { get; set; }
public string TitreR { get; set; }
public string Desc { get; set; }
//public int Position { get; set; }
public int Rating { get; set; }
public string Tags { get; set; }
public virtual int SectionId { get; set; }
public virtual int UserId { get; set; }
public virtual ICollection<Links> Links { get; set; }
}
public class Section
{
[Key]
public int SectionId { get; set; }
public string Titre { get; set; }
public virtual ICollection<Tags> Tags { get; set; }
public virtual ICollection<Ressource> Ressources { get; set; }
//public Section() { this.Tag=new List<string>(); }
}
And when I want to delete a Ressource, I have this error:
The operation failed: The relationship could not be changed because one or more of the foreign-key properties is non-nullable. When a change is made to a relationship, the related foreign-key property is set to a null value. If the foreign-key does not support null values, a new relationship must be defined, the foreign-key property must be assigned another non-null value, or the unrelated object must be deleted.
error line:
_db.Entry(R).State = EntityState.Deleted;
_db.SaveChanges(); // error line
PS: It was working before I added the Filename attribute to the Links class... Any idea how to solve it? Thank you
Make foreign key nullable (i.e. change it's type from int to int?):
public virtual int? RessourceId { get; set; }
That means you can have links without resource.
I recently came across this strange problem with Entity Framework Code First.
My class looks like this
public class Status
{
[Key]
public int StatusID { get; set; }
public string Name { get; set; }
public int MemberID { get; set; }
[ForeignKey("MemberID")]
public virtual Member Member { get; set; }
public int PosterID { get; set; }
[ForeignKey("PosterID")]
public virtual Member Poster { get; set; }
public virtual ICollection<StatusLike> StatusLikes { get; set; }
public virtual ICollection<StatusComment> StatusComments { get; set; }
}
My Member class looks like this
public class Member
{
[Key]
public int MemberID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Bio { get; set; }
public virtual ICollection<MemberCourseTaken> MemberCourseTakens { get; set; }
public virtual ICollection<Status> Statuses { get; set; }
public virtual ICollection<Club> FoundedClubs { get; set; }
public string EmailAddress { get; set; }
public string Password { get; set; }
public string Phone { get; set; }
public int AccountSourceID { get; set; }
public AccountSource AccountSource { get; set; }
public int AddressID { get; set; }
public Address Address { get; set; }
public string ProfilePhoto { get; set; }
public int MemberRankID { get; set; }
public MemberRank MemberRank { get; set; }
public DateTime Created { get; set; }
public DateTime Modified { get; set; }
}
And for whatever reason the database table that is created has the following columns
StatusID
Name
MemberID
PosterID
Member_MemberID
with MemberID, PosterID, and Member_MemberID being foreign keys.
How can I keep Member_MemberID from being generated?
Your Member_MemberID column is created because of the Member.Statuses property. I can imagine that this is not what you want. Probably members and statuses should exist independent of each other, so you need a junction table.
I don't know if you already use the OnModelCreating override of the DbContext, but that's the place to change the mapping between Member and Status:
protected override void OnModelCreating(DbModelBuilder mb)
{
mb.Entity<Member>().HasMany(m => m.Statuses).WithMany();
}
This will create a table MemberStatuses table with the two Id columns as foreign keys. This is a way to model a many-to-many relationship without a navigation property on the "other" side of the association. (I don't think you want a Members property in Status).
I've seen this before. In my case (Using EF 6.1), it was because my Fluent API Mapping was set up like so:
// In my EntityTypeConfiguration<Status>
HasRequired(x => x.Member).WithMany().HasForeignKey(x => x.MemberID);
That code works perfectly fine, but it doesn't tell EF that my Member class's Collection Navigational Property Status ha been taken into account. So, while I explicitly handled the existence of a Member Navigational Property in my Status Class, I now left an orphaned related collection property. That orphaned property, being a collection, tells EF that my Status class needs to have a Foreign Key to it. So it creates that on the Status Class.
To fix it, I had to be 100% explicit.
HasRequired(x => x.Member).WithMany(x => x.Statuses).HasForeignKey(x => x.MemberID)
It could bee that your Statuses Collection property in Member needs an attribute telling it that it is already considered, and not to go auto-creating mappings. I don't know that attribute.