Im using EF 6 to build my app. Ive got entity User and entity BoughtProduct
In User:
this.BoughtProducts = new HashSet<BoughtProduct>();
Then I do some logic in my app. Sometimes I do sth like this:
MyUser.BoughtProducts.Clear();
then when I save changes to my context I have following error:
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.
What am I doing wrong?
Related
I have two tables, which have a 1:n relationship. I used the following EF Code First relationship definition:
modelBuilder.Entity<MyPrimary>()
.HasMany(x => x.MyOthers)
.WithRequired()
.HasForeignKey(x => x.primary_id)
.WillCascadeOnDelete();
Note that primary_id is a non-nullable column, that's also why I set the relationship to .WithRequired() - a MyOther needs to have a MyPrimary and cannot exist on its own.
Now I have the following code:
myPrimary.MyOthers.Clear();
ctx.SaveChanges();
And I receive the following exception:
System.InvalidOperationException : 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.
Why? Shouldn't all the MyOther instances in myPrimary.MyOthers be cascade-deleted and therefore the non-nullable FK should not be a problem?
When you call .Clear() EF trying to unassign MyOther from MyPrimary, It is not smart enough to figure out that you want to delete MyOther records. Maybe after clear you will decide to add these MyOther records to another MyPrimary record. So you should to mark these records as deleted explicitly. You can write method similar to this
public void MarkForDeleteItems<T>(ICollection<T> collection) where T : class
{
foreach (var collectionItem in collection.ToList())
{
ctx.Entry(collectionItem).State = EntityState.Deleted;
}
}
And then use it
MarkForDeleteItems(myPrimary.MyOthers);
ctx.SaveChanges();
Also WillCascadeOnDelete meaning that when you delete MyPrimary record than database will delete all MyOthers records which related to MyPrimary.
I have a table named "Notaries":
NotaryID int,
NotaryName nvarchar(MAX)
and table named "NotaryPhones":
PhoneID int,
NotaryID int,
PhoneNumber nvarchar(50)
So, relationship "one-to-many". Now I want to clear all phones, depending on the notary. My code:
Notary.Models.Notary notary = (from i in db.Notaries where i.NotaryID == model.NotaryID.Value select i).FirstOrDefault();
notary.CityID = Convert.ToInt32(model.City.SelectedItem);
notary.NotaryPhones.Clear();
db.SaveChanges();
but I get an 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.
If I remove the string
notary.NotaryPhones.Clear();
it works. I understand, that this is a trivial thing, but don't understand how to fix it
What's going on is that your notary.NotaryPhones.Clear(); is removing the foreign-key reference from your NotaryPhone table to your Notary table. Because this is set up as a non-nullable key so that you don't have orphan phone records, you're receiving that error.
What you'll want to do instead is set up a method in your repository that will call context.NotaryPhones.Remove(**instance variable pointing to one of the phones to delete**); and that will delete them from the database.
CLARIFICATION
The reason why it removes the foreign key reference is that notary.NotaryPhones.Clear() just removes those objects from the notary object. The objects will continue to exist the way that you have written this.
So when the .Clear() is executed, it takes your phone.NotaryID property and gets rid of the ID pointer to the notary. Since you're not assigning it anything else, the value it tries to assign is null (the only value that couldn't possibly point to a Notary object). But, because you have it set up as an int, and not an int?, it can't make that assignment and it throws the error you see.
You said you're trying to delete the objects, so you need to remove them from the database. To do that, you do what I explained above.
please excuse the example if there are syntax errors, I am currently working in VB but the approach is the same
foreach (NotaryPhones np in notary.NotaryPhones)
{
db.NotaryPhones.DeleteObject(np);
}
then save your changes with
db.SaveChanges();
Clear just removes entity from the related collection. it doesn't remove entity from database. you have to delete each NotaryPhone from corresponding DbSet.
I have a DBFirst EntityFramework 6.1 solution that i'm trying to generate off of. When i add a table that only contains two foreign keys the table is turned into two associations and I can not directly access the table anymore. This is neat for navigation in the code but makes it a pain in the ass to delete records from the table.
Is there a way to prevent this behavior and gain direct access to the table as an entity?
For example i am unable to remove an entry in the association because i get 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.
For example here is how my database sees the structure.
Here is how it appears in entity framework. Notice that the CorporateDataShareVisible table is missing and instead two new associations are created.
The CorporateDataShareVisible table should be able to be deleted and added to at will but any changes i make seem to stop it from working.
Add a primary key to your table that has only foreign keys. EF uses the primary key to keep track internally of the element. Without a primary key it doesnt know which element was modified and how to send that back to your RDBMS.
I prefer surrogate keys i.e auto incrementing integers.
You can also add the primary key by making it a composite key of both the foreign keys
I generated a model (with EF) from my database ,i set Code Generation Strategy to None and then i created my (POCO) classes with the same properties as in model and now my business class are decoupled from EF.
(My Model has only two classes:Question and Answer. One Question can have more Answers).
And this code is good:
Question q=db.Questions.First();
Answer a=q.Answers.First();
a.Title+=" modified";
q.Answers.Add(new Answer(){Text="bla bla bla"});
db.SaveChanges();
I have a little inconvenience:
Question q=db.Questions.First();
Answer a=q.Answers.First();
q.Answers.Remove(a);
db.SaveChanges();
With this code I have this error:
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.
But this can be done with:
Question q=db.Questions.First();
Answer a=q.Answers.First();
db.Answers.DeleteObject(a);
So why do i need Castle Windsor(Dynamic Proxy) when my EF i good enough?EF works as well as Castle Windsor ,it inherit my POCO classes at Runtime.
1)What role have DynamicProxy(Castle Windsor) and AOP(PostSharp) if i have EF?
2)What do i need Dynamic Proxy(with reflection) when i can inherit my POCO classes at compiled time?(This is optional,possible to create another question for this subject)
Sorry for my bad English.
I have a very precise gap of knowledge of the assignement of the entity keys in entity framework.
When you set a variable to become the entity key of an entity, if you are doing code first or model first it sets the column as identity but what if I assign the entity key to 0 in the default constructor of my model first class, what does EF do?
Will EF notice that it was an auto assignement and ignore the default value I set in the constructor?
Or should I never assign an entity key other than when im retrieving data?
So far I have yet to see the first scenario where there is absolutely no alternative for setting an EntityKey object. But I assume you're not referring to that but to setting a key value.
Setting a primary key value is hardly ever necessary when the key is generated by the database (identity column). If you want EF to insert an entity you don't set the primary key, but you set its EntityState to Added (either directly or indirectly).
I can think of one scenario where setting primary key values is useful: using stub entities. For example, suppose you know that object A with id value 3 must be deleted, but object A has not been fetched from the database. So there is no object which state can be changed to Deleted. In that case you can prevent a roundtrip to the database by creating a stub entity A that only has its Id value filled, attach it to a context as Deleted and save changes.