Entity Framework: removing entity when One-to-One PK association is specified - entity-framework

I have existing DB with the following structure:
I'm using EF fluent API to configure relationships between tables:
public GroupEntityConfiguration()
{
HasMany(x => x.Employees).WithRequired().HasForeignKey(x => x.GroupId).WillCascadeOnDelete(true);
}
public EmployeeEntityConfiguration()
{
HasOptional(x => x.InnerGroupMember).WithRequired();
}
With this configuration applied I can add new Employee, new InnerGroupMember or fetch data. The problem appears when I try to remove Employee. Then I get an exception:
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.
As far as I understand above exception is connected with GroupId foreign key. Trying to fix it I'm adding following line to EmployeeEntityConfiguration:
HasKey(x => new { x.Id, x.GroupId});
But after adding it I get another exception which I believe is connected with InnerGroupMember object:
Invalid column name 'Guest_Id'. Invalid column name 'Guest_GroupId'.
If I comment out InnerGroupMember navigation property and remove it's configuration, Employee can be removed.
Could you please give me a hint what I'm doing wrong and how to configure entities to be able to perform all needed operations? Thanks!

I have an existing Group entity and I want to remove Employee from the Employees Group collection:
var group = groupRepository.Find(groupId);
group.RemoveEmployee(employeeId);
_unitOfWork.Save();
RemoveEmployee function inside Group entity looks like this:
public void RemoveEmployee(int employeeId)
{
var employee = Employees.Single(n => n.Id == employeeId);
Employees.Remove(employee);
}
That's why I get an exeption:
The relationship could not be changed because one or more of the foreign-key properties is non-nullable....
After reading this post I wanted to fix it adding HasKey(x => new { x.Id, x.GroupId}); function inside EmployeeEntityConfiguration what leads to the second exception:
Invalid column name 'Guest_Id'. Invalid column name 'Guest_GroupId'.
Actually I made this step (I mean adding HasKey function) without changing DB structure. To make it work, inside Employees table I have to create composite key - combination of Id and GroupId which is also a foreign key. This modification forces changes inside InnerGroupMembers table. DB structure looks now as following:
Now I'm able to remove Employee in a way I showed at the beginning.
Anyway I'm not going for this solution. They are different ways to achieve what I want. Here are some links:
Removing entity from a Related Collection
Delete Dependent Entities When Removed From EF Collection
The relationship could not be changed because one or more of the
foreign-key properties is non-nullable

For one-to-one relationships cascading delete is not enabled by default, even not for required relationships (as it is the case for required one-to-many relationships, that is: The WillCascadeOnDelete(true) in your one-to-many mapping is redundant). You must define cascading delete for a one-to-one relationship always explicitly:
HasOptional(x => x.InnerGroupMember).WithRequired().WillCascadeOnDelete(true);
When you delete an Employee now, the database will delete the related InnerGroupMember as well and the exception should disappear.

Related

Entity Framework is appending "1" to table name and query is failing

We have an e-commerce site that uses Web Api and Entity Framework. I recently had created an ApiController for an entity called "BundleProduct". When I call the GET method on the controller, I get a System.Data.SqlClient.SqlException: "Invalid object name 'dbo.BundleProducts1'."
Using the VS debugger, this is the query that was being executed (there are only two columns in this table, with together form a primary key):
SELECT
[Extent1].[Fk_BundleID] AS [Fk_BundleID],
[Extent1].[Fk_ProductID] AS [Fk_ProductID]
FROM [dbo].[BundleProducts1] AS [Extent1]
There is no "BundleProducts1" table, it should be called "BundleProducts". I did a search in the code and cannot find any instances where the name "BundleProducts1" is used.
The BundleProducts table represents a many-to-many relationship between a "Bundles" table and "Products" table. This particular table has only two columns and both together are the primary key. I did look at the DbContext class and the only references it has to BundleProducts are:
public DbSet<BundleProduct> BundleProducts { get; set; }
modelBuilder.Entity<Bundle>()
.HasMany(e => e.Products)
.WithMany(e => e.Bundles)
.Map(m => m.ToTable("BundleProducts")
.MapLeftKey("Fk_BundleID")
.MapRightKey("Fk_ProductID"));
Why is EF appending a "1" to the table name and what can I do to change this?
When you use the many-to-many mapping (HasMany - WithMany), EF will use a hidden association class named BundleProducts.
The problem is that you also added a visible class BundleProducts. EF tries to do what you instructed it to do: map both classes to a table and then it encounters a name conflict. The visible class is victimized and is renamed.
You either have to remove the visible class from your model, or transform the many-to-many mapping into two one-to-many mappings with BundleProducts in the middle: Bundle 1 - n BundleProduct n - Product.

How to get foreign key value from not fetched relationship?

Having two entities defining relationship by #ManyToOne and #OneToMany, how can I get foreign key without asking from related object and just by looking at defining tables? How do I get OWNER_ID from Owned by something like owned.getOwnerId() instead of owned.getOwner().getId() and still be able to owned.getOwner()?
Map the field in your entity as a basic mapping allows you to use the foreign key directly. You can keep the object reference mapping as well, but one of the two mappings must then be marked as insertable=false, updatable=false so that JPA knows which mapping controls the field in the event they show different values.

Entity Framework Code first mapping without foreign key

I have two tables:
Requirement
ID (int) PK
ClientID (int)
JobNumber (int)
Comment
ID (int) PK
Job_ID (int)
Comment (varchar)
The tables don't have foreign keys and there's no possibility of adding any. I'm trying to map them in EF. I have classes for each and I'm trying to define the relationship in fluent code to map the Comment.Job_ID to the Requirement.JobNumber. A requirement can have many comments. Requirement has a list of Comments and Comment has a Requirement property.
I have this mapping setup:
modelBuilder.Entity<Comment>().HasRequired(c => c.Requirement)
.WithMany(s => s.Comments)
.HasForeignKey(f => f.Job_ID);
I'm stuck trying to get Comment.Job_ID to map to Requirement.JobNumber.
Any help appreciated.
It's not possible. With Entity Framework the entity that the Comment.Requirement navigation property is refering to is generally identified by the (primary) key property in Requirement, i.e. by ID. There is no mapping option to define that the target property is anything else than the key property - like JobNumber or another non-key property.
I could only imagine that you could "fake" the primary key property in the model to be JobNumber instead of ID (given that JobNumber is unique in the Requirement table):
modelBuilder.Entity<Requirement>().HasKey(r => r.JobNumber);
I don't know if that could have other unwished side effects. (For sure it doesn't work if JobNumber is not unique because EF wouldn't allow to have more than one entity with the same key attached to a context and updates/deletes and so on wouldn't find the correct record in the database.) It feels wrong and hacky to me. I honestly wouldn't even try that, live with the fact that you don't have a real foreign key relationship in the database, forget the navigation properties Requirement.Comments and Comment.Requirement and use manual joins in LINQ to relate the table data/entities as I need them in a given situation.

How to refer to foreign key without HasForeignKey()

Using EF 4.0 with the 4.1 upgrade for POCO / code-first.
OK so I have a domain model where type Car has, in a collection, multiple objects of type Part. So a one:many relation.
HasMany(v => v.Parts)
.WithRequired()
.HasForeignKey(v => v.CarId)
.WillCascadeOnDelete();
The problem with this is that it requires me to add a CarId property to my Part type. This is leaking ORM detail into my domain model - which is bad. Marking everything virtual is annoying enough.
Looking at the XML doc comment for the HasForeignKey() method says this:
Configures the relationship to use
foreign key property(s) that are
exposed in the object model. If the
foreign key property(s) are not
exposed in the object model then use
the Map method.
That's great and all. But it introduces a catch-22 situation because if I refactor my Part type by removing the CarId property that I don't want and update my EF model builder to not bother with mapping that property. Then as you can imagine it means I cannot then call HasKey() for defining the composite key, ala:
HasKey(v => new { v.CarId, v.PartId });
HasKey() doesn't appear to support defining the keys based upon non-Property lambdas.
What is the solution here?
If you absolutely don't like to have foreign key properties in your model you could remove the convention to detect FK properties to avoid that EF marks properties automatically as FK properties ...
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions
.Remove<NavigationPropertyNameForeignKeyDiscoveryConvention>();
}
... and then simply don't specify the FK property in your mapping:
HasMany(v => v.Parts)
.WithRequired()
.WillCascadeOnDelete();
You still need CarId in your model because it is part of the primary key, but this way it doesn't act anymore as foreign key property.
Just an idea, I am not sure if it works.
Well, what about adding a new key field to CarParts table like CarPartId, so you would not need the composite key. (Composite Key support is not that great when working with ORMs.)

Entity Framework: Creating and inserting many to many relationships

I am new to the Entity Framework and am looking for some direction on creating the relationships between an entity and related many-to-many associative entities and inserting them in one operation.
The relevant entities in my EDMX:
Participant
ID
Name
ParticipantCustomField
ParticipantID
CustomFieldID
Value
CustomField
ID
Name
I need to insert a single Participant entity and many ParticipantCustomField entities. The related CustomField entity will already be in the database at the time of insert.
I have a repository create method which accepts a Participant and a collection of ParticipantCustomField objects:
public Participant CreateParticipant(Participant participant, List<ParticipantCustomField> customFields)
{
// need to establish relationship here
entities.AddToParticipant(participant);
entities.SaveChanges();
return participant;
}
I have tried several methods but cannot figure out how to properly relate the collection of ParticipantCustomField objects with the new Participant before the insert. I know the CustomFieldID foreign key as that is set outside of this method, but the ParticipantID foreign key cannot be set until the Participant is inserted.
I guess since this is the Entity Framework I shouldn't be focused on "foreign keys", which I think are only there because my associative table has a third column, but on relations.
Thanks for any help!
You don't need to set ParticipantCustomField.ParticipantId. The framework will do that for you. Instead you'd do something like:
foreach (var cf in customField)
{
participant.CustomFields.Add(cf);
}
entities.AddToParticipant(participant);
entities.SaveChanges();
return participant;
I'm making some presumptions about your mappings here, but this should give you the general idea.