I'm using ASP.NET 5 with Entity Framework 7.
I have this models:
public class ParentModel
{
public Guid Id { get; set; }
public virtual ChildModel Children { get; set; }
}
public class ChildModel
{
public Guid Id { get; set; }
public virtual AnotherChildModel AnotherChild { get; set; }
}
public class AnotherChildModel
{
public Guid Id { get; set; }
public string Text { get; set; }
}
When I'm trying to add ParentModel to database, it doesn't automatically add ChildModel and AnotherChildModel to database, while ParentModel completely correct in code, for example:
var parent = new ParentModel() { Children = new ChildModel() { AnotherChild = new AnotherChildModel() { Text = "sometext" }}};
So, simple parentSet.Add(parent) doesn't work, is there another way, except for manually adding all models in sets?
EDIT:
Exception I have:
DbUpdateException: An error occurred while updating the entries. See the inner exception for details.
SqlException: The INSERT statement conflicted with the FOREIGN KEY constraint "FK_ParentModel_ChildModel_ChildrenId". The conflict occurred in database "aspnet5-WebApplication1-922849d0-b7da-4169-8150-9a2d05240a47", table "dbo.ChildModel", column 'Id'. The statement has been terminated.
In the current RC1 version of EF7, Add() only recursively adds adhering objects in collections (i.e. true children), not referenced entities, as EF6 did.
So if you'd have the following model (that's more consistent with the names you chose) ...
public class ParentModel
{
public Guid Id { get; set; }
public virtual ICollection<ChildModel> Children { get; set; }
}
... the children would also be added by the single statement parentSet.Add(parent).
I don't know if this is intended behavior. The RC has already proven to come with issues a "release candidate" shouldn't have. But maybe it's an OO-inspired design decision that parents encapsulate their children and not the reverse.
Related
I've got 2 entities with a 1-0..1 relationship between them, but restrictions on what the generated DB schema can look like.
So 1 Vehicle to 0 or 1 RecVehicle entity
I need to be able to have a navigation property from Vehicle to RecVehicle, but without the DB Schema for the Vehicles table having a FK to RecVehicle. The PK of the RecVehicle table should be the Id of the Vehicle entity it relates to.
We are using EF code first
public class Vehicle
{
[Key]
public int Id { get; set; }
public virtual RecVehicle RecVehicle { get; set; } // Need to be able to use as navigation
}
public class RecVehicle
{
[Key]
public int VehicleId { get; set; }
[ForeignKey("VehicleId")]
public Vehicle Vehicle { get; set; }
}
The generated schema needs to be something like this:
Vehicles
[ Id(int, pk, not null), ...] <-- no FK column to RecVehicles
RecVehicles
[ VehicleId(int, pk, fk, not null), ...]
Originally what I had tried something like this:
public class Vehicle
{
[Key]
public int Id { get; set; }
[InverseProperty("Vehicle")]
public virtual RecVehicle RecVehicle { get; set; } // Need to be able to use as navigation
}
but this causes this exception:
Unable to determine the principal end of an association between the types 'Contract.Entities.Vehicle' and 'Contract.Entities.RecVehicle'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.
I'm not sure what fluent API relationships to setup to make this work, nor the correct set of data annotations to make this work, or if it's even possible.
Reasoning
The reason there is strict limitations on the DB schema is our Data team has a migration/data import process that we can not alter
We have an existing code base that uses the navigation property in many places (2 teams, desync in schema) so changing to use a lookup in code requires many changes in the code base that we are trying to avoid.
The RecVehicle can be connected to multiple Vehicles
Can you try the following navigation property?
public virtual ICollection<RecVehicle> RecVehicle { get; set; }
instead of
public virtual RecVehicle RecVehicle { get; set; }
Due to the RecVehicle primary key this list only maximum contains one element
Ended up being able to get this relationship to work like this:
public class Vehicle
{
[Key]
public int Id { get; set; }
public virtual RecVehicle RecVehicle { get; set; }
}
public class RecVehicle
{
[Key]
public int VehicleId { get; set; }
[ForeignKey("VehicleId"), Required] //<--- Required attr fixed the principal/dependent confusion EF was having
public virtual Vehicle Vehicle { get; set; }
}
So we have this legacy DB to which we have no control and cannot modify in any way or form. Any of the tables in said DB have foreign keys and we are using EF 6 to access it. We created our model and, up until now, things were OK.
Now we are dealing with the following, very common, structure:
[Product] [ProductGroupDetails] [ProductGroup]
ProductID ProductID ProductGroupID
... ProductGroupID .....
Both Product and ProductGroup tables have additional fields which are not relevant right now. The two fields in the ProductGroupDetails conform its primary key.
After adding these three tables to the model I manually added the associations between them by right clicking on the diagram and selected the Add New -> Association option.
After running the tt file I get these entities:
public partial class ProductGroup
{
public ProductGroup()
{
this.ProductGroupDetails = new HashSet<ProductGroupDetail>();
}
public int ProdGroupID { get; set; }
public virtual ICollection<ProdGroupDetail> ProdGroupDetails { get; set; }
}
public partial class ProdGroupDetail
{
public int ProdGroupID { get; set; }
public string ProductID { get; set; }
public virtual Product Products { get; set; }
public virtual ProdGroupHead ProdGroupHead { get; set; }
}
public partial class Product
{
public Product()
{
this.ProductGroupDetails = new HashSet<ProductGroupDetail>();
}
public string ProductID { get; set; }
public virtual ICollection<ProductGroupDetail> ProductGroupDetails { get; set; }
}
I would have expected for the ProductGroupDetails entity not to exist, the Product one having a ProductGroups collection and the ProductGroup to have a Products collection.
Of course this makes it challenging when creating a new Product Group since to the new ProductGroup instance I would have to add an instance of ProductGroupDetail for each group but the ProdGroupID property would be empty since I do not know it yet. Normally I would just add instances of Product to the Products collection and upon save EF would work its magic.
Is there a way I can coerce the edmx so that the ProductGroupDetail entity is not created and the other ones end up having the expected collections?
I am developing a solution using EF 5 in VS 2012 and I am puzzled about the correct way to specify entity relationships when adding and updating an entity.
These are my main classes where notifier is a person:
public class Notifier : Person
{
public bool IsValid { get; set; }
public int NotifierTypeID { get; set; }
public virtual NotifierType NotifierType { get; set; }
public int MyCaseID { get; set; }
public virtual MyCase MyCase { get; set; }
}
public abstract class Person
{
public int PersonID { get; set; }
public String Name { get; set; }
}
Notifiers belong to cases
public class MyCase
{
public int MyCaseID { get; set; }
public DateTime DateOfNotification { get; set; }
public virtual ICollection<Notifier> Notifiers { get; set; }
}
and have a type:
public class NotifierType
{
public int NotifierTypeID { get; set; }
public string NotifierTypeName { get; set; }
}
I am exposing the foreign keys between notifiers and cases and notifier types.
The method I use to add/update a notifier is:
using (MyContext dbContext = new MyContext(connectionString))
{
notifier.MyCaseID = MyCaseID;
notifier.NotifierTypeID = notifierView.NotifierTypeID;
// **** the puzzling line ****
notifier.NotifierType = dbContext.NotifierTypes.Find(notifierView.NotifierTypeID);
//dbContext.Database.Log = s => System.Diagnostics.Debug.Write(s);
dbContext.Entry(notifier).State = notifier.PersonID == 0 ? EntityState.Added : EntityState.Modified;
dbContext.SaveChanges();
// save the ID in case it's new
notifierViewReturn.PersonID = notifier.PersonID;
}
I am puzzled by the line after the comment **** the puzzling line **** above. I am specifying the foreign keys explicitly and don't need the this line if I am adding a notifier but I do need it if I am updating the object, otherwise it throws an exception.
The exception is
Message=A referential integrity constraint violation occurred:
The property values that define the referential constraints are not
consistent between principal and dependent objects in the relationship.
Can anyone please explain why this line is needed at all. Thanks
When you update an existing entity, before you make changes the entity already has NotifierType (navigation property) and NotifierTypeID populated. If you then change NotifierTypeID but don't update NotifierType, Entity Framework detects a potential inconsistency (NotifierTypeID != NotifierType.NotifierTypeID) and throws the exception you are getting. This is why you need to set both when updating. When adding, you don't have this issue because only one of the IDs is defined (NotifierTypeID, but not NotifierType.NotifierTypeID), so it just uses that one.
If you want to avoid going to retrieve the notifier type for updates, you should be able to just set it to null instead, and in that case there will be no discrepancy and it can just use the NotifierTypeID that you set:
notifier.MyCaseID = MyCaseID;
notifier.NotifierType = null;
notifier.NotifierTypeID = notifierView.NotifierTypeID;
Hope that helps!
In my AspNet MVC 3 project when I try to scaffold an entity which has a One to Zero or One relationship with another entity I get "An item with the same index has already been added" error.
Essentially this happens when the Primary Key of the related table is also a Foreign Key.
At the moment my workaround is
Add an Id column to the related table and make it the primary key
Add Unique Key to the Foreign Key Column.
The problem with this is that EF will generate an ICollection navigation property for the related entity instead of just a property of the related entity type (which I can set to null in case of zero related entities)
Is this a know bug?
Am I doing something wrong?
Is there a better work around to get rid of the ICollection navigation property?
See my answer on this question:
How do I code an optional one-to-one relationship in EF 4.1 code first with lazy loading and the same primary key on both tables?
That's the example code with the correct configuration.
public class ZoneMedia
{
public int ZoneMediaID { get; set; }
public string MediaName { get; set; }
public int Width { get; set; }
public int Height { get; set; }
public virtual ZoneMediaText MediaText { get; set; }
}
public class ZoneMediaText
{
public int ZoneMediaID { get; set; }
public string Text { get; set; }
public int Color { get; set; }
public virtual ZoneMedia ZoneMedia { get; set; }
}
public class TestEFDbContext : DbContext
{
public DbSet<ZoneMedia> ZoneMedia { get; set; }
public DbSet<ZoneMediaText> ZoneMediaText { get; set; }
protected override void OnModelCreating (DbModelBuilder modelBuilder)
{
modelBuilder.Entity<ZoneMedia>()
.HasOptional(zm => zm.MediaText);
modelBuilder.Entity<ZoneMediaText>()
.HasKey(zmt => zmt.ZoneMediaID);
modelBuilder.Entity<ZoneMediaText>()
.HasRequired(zmt => zmt.ZoneMedia)
.WithRequiredDependent(zm => zm.MediaText);
base.OnModelCreating(modelBuilder);
}
}
class Program
{
static void Main (string[] args)
{
var dbcontext = new TestEFDbContext();
var medias = dbcontext.ZoneMedia.ToList();
}
}
You can also achieve this with DataAnnotations, but I generally prefer to keep my entity models as POCOs.
Try to use the [Key] attribute to the intended primary key. You may need to import the namespace System.ComponentModel.DataAnnotations
Also check the documentation about the full implementation of this namespace.
http://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.aspx
Using the method described here, I am attempting to delete a parent record and all the associated child records. However, what happens is the parent is deleted as expected, but child record key field is updated to NULL instead of being deleted.
I also set the child table foreign key's Delete Rule to Cascade, and deleting from the parent table in SQL Server Management performs the cascade delete as expected.
I started by following this walkthough, and modifying the code to perform a delete.
this is the code:
using (var db = new ProductContext())
{
var food = db.Categories.Find("FOOD");
((IObjectContextAdapter)db).ObjectContext.LoadProperty(food, f => f.Products);
db.Categories.Remove(food);
int recordsAffected = db.SaveChanges();
Is there something I'm missing? Or is orphaned child records the intended result?
The association between Product and Category has been configured as optional due to the fact that the foreign key property on Product class (i.e. Product.CategoryId) has a nullable type (i.e. string). To make this association required so that the child entity is get deleted as a result of deleting the parent you need to mark CategoryId as Required as I did in the following code:
public class Category
{
public string CategoryId { get; set; }
public string Name { get; set; }
public virtual ICollection<Product> Products { get; set; }
}
public class Product
{
public int ProductId { get; set; }
public string Name { get; set; }
[Required]
public string CategoryId { get; set; }
public virtual Category Category { get; set; }
}