Is there any way to save a child object in a parents child object collection and also setting it to a navigation property on the parent without round tripping to the database? example below doesn't work
public class Parent
{
int Id { get; set; }
int? ChildId { get; set; }
Child Child { get; set; }
public virtual ICollection<Child> Children { get; set; }
}
public class Child
{
int Id { get; set; }
public Parent Parent { get; set; }
}
....
var p = new Parent();
var c = new Child();
p.Child = c;
p.Children.Add(c);
Context.Set<Parent>().Add(p);
Context.SaveChanges();
EDIT
The example above throws this error when 'savechanges()' is called.
Unable to determine a valid ordering for dependent operations. Dependencies may exist due to foreign key constraints, model requirements, or store-generated values.
Related
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; }
}
I have two classes with an parent-child (1:n) relationship and want to detect when the parent has been changed by adding a child to it.
I have overriden the SaveChanges method of the context:
public override int SaveChanges()
{
var ctx = ((IObjectContextAdapter)this).ObjectContext;
ctx.DetectChanges();
var entries = ctx.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Deleted | EntityState.Modified);
foreach (var entry in entries)
{
if (entry.IsRelationship)
{
Console.WriteLine("Relationship");
}
else
{
Console.WriteLine("Entity");
}
}
return base.SaveChanges();
}
As expected, when adding a child to the parent I get an entity entry for the child and a relationship entry for the parent-child relationship. But as soon as the child class contains a key property for the parent, I no longer get any relationship entries for this relationship.
class Class1
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int Id { get; set; }
public ICollection<Class2> Class2s { get; set; }
}
class Class2
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int Id { get; set; }
public Class1 Parent { get; set; }
public int ParentId { get; set; } // <-- no relationship entries if present
}
Is this expected behavior? How can I detect relationship changes when the id column is present?
Can someone shed light onto this?
I have three objects. Firstly, a Root object
public class Root
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
}
This is the basis for my composite key, used in Parent,Child:
public class Parent
{
[Key, Column(Order = 0)]
public int RootId { get; set; }
public Root Root { get; set; }
[Key, Column(Order = 1)]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public ICollection<Child> Children { get; set; } = new Collection<Child>();
}
public class Child
{
[Key, Column(Order = 0)]
public int RootId { get; set; }
public Root Root { get; set; }
[Key, Column(Order = 1)]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public int ParentId { get; set; }
[ForeignKey("RootId, ParentId")]
public Parent Parent { get; set; }
}
I add a new parent object with multiple children
Parent result = new Parent
{
RootId = rootId
};
foreach (var child in children)
{
result.Children.Add(new Child
{
RootId = rootId
});
}
_dbContext.Parents.Add(result);
_dbContext.Save();
However, I get an exception whenever I have multiple Root objects in my database:
The INSERT statement conflicted with the FOREIGN KEY constraint "FK_dbo.Children_dbo.Parents_RootId_ParentId". The conflict occurred in database "Test", table "dbo.Parents".
When I delete the foreign key constraint in my database, I can see that EF is somehow ignoring the RootId = rootId that I set. It uses a different one instead. The ParentId is correctly set, but obviously this results in a FK that doesn't exist.
I want to commit the parent and its children in one Save call. I've tried adding the children to _dbContext.Children after adding the parent to _dbContext.Parents, I've tried first adding the Children, to no avail.
Can someone shed light on this? I'm running out of ideas on what to check to understand what I'm doing wrong..
Edit: I'm using Entity Framework 6.1.3.
I have model Page:
public int Id{ get; set; }
public string Name { get; set; }
I want to have children pages there:
public int Id{ get; set; }
public string Name { get; set; }
public List<Page> Childrens { get; set; }
What the best way to setup non required children items of same model?
The way I went about it requires a few additional properties in your model (I'm using the virtual` keyword for my navigation properties because I required lazy loading):
public class Page
{
public int Id { get; set; }
public string Name { get; set; }
public int? ParentID { get; set; } // Nullable int because your Parent is optional.
// Navigation properties
public virtual Page Parent { get; set; } // Optional Parent
public virtual List<Page> Children { get; set; }
}
Then, using a foreign key association, you can configure the relationship like so (this is my Page mapping):
// You may be configuring elsewhere, so might want to use `modelBuilder.Entity<Page>()` instead of `this`
this.HasMany(t => t.Children)
.WithOptional(t => t.Parent)
.HasForeignKey(x => x.ParentID);
Essentially, every child is aware of its parent, and as a result of the navigation properties, you can explore the relationship from both sides.
Given something like:
public class Parent
{
public int Id { get; set; }
public List<Child> Children { get; set; }
}
// There is no reference to the parent in the object model
public class Child
{
public int Id { get; set; }
public string MyProperty { get; set; }
}
is it possible to load only a child matching a particular condition, for a given Parent ID, without also loading the parent entity?
I have seen solutions that use projection to load the parent and zero or more children matching a condition.
If I understand you correctly, this should do it; it puts the conditions you want on both the parent and child, but selects only the child.
from parent in db.Parents
from child in parent.Children
where parent.Id = 4711 &&
child.MyProperty == "olle"
select child;