Error Deleting a child object from its parent - vb.net

I'm using vb.net 2013, Entity Framework 6 and SQL Server 2008 R2.
I'm trying to delete from child entities, and this does not work. But if I try to delete directly from context, this works.
In my database I have 2 tables Students and Result.
This is my code that does not work :
Dim context as Myentities = New myentities.
Dim s as student.
Dim lresult as new list (of result)
s = context.students.where(Function(t1) t1.value>5).Tolist.first
lresult = (from t in s.results where t.vl2=7 select t).Tolist
for each rs as result in lresult
if rs.vl3=11 then s.results.remove(rs)
Next
Context.SaveChanges
This code produces an error on the last line (context.SaveChanges) :
An unhandled exception of type 'System.InvalidOperationException' occurred in EntityFramework.dll
Additional information: 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.
But if I change the line that delete the item, like below, it works :
Dim context as Myentities = New myentities.
Dim s as student.
Dim lresult as new list (of result)
s = context.students.where(Function(t1) t1.value>5).Tolist.first
lresult = (from t in s.results where t.vl2=7 select t).Tolist
for each rs as result in lresult
if rs.vl3=11 then context.results.remove(rs)
Next
Context.SaveChanges
Why does my first snippet of code not work?

I guess you defined the relationship between Students and Results by adding a Foreign Fey from Results to Students, a non-nullable field named StudentId or similar. When you do the Remove from the parent Student collection of Results, EF does not really remove the deleted Result from the context, EF just removes the relationship between them and sets the StudentId value in your Result child as null, but the child remains in the context. So you get an orphaned child that can't be saved because the FK field is null.
The problem is that your relationship conceptually is an Identifying relationship, which means that you can't have a Result that does not belong to a Student. But EF sees your relationship as non-identifying.
You have two options:
Make EF recognize the relationship as an Identifying relationship, by adding the Foreign Key field StudentId to the Primary Key of Results. You will have a composite key. This way EF will take care of removing the child from the context when you remove it from the collection in the parent.
Leave the PK as is, and explicitly remove the child from the context before saving. That is, you do both the Removefrom the parent collection and the context.Remove.
Usually the second option is preferred because composite keys are a bit complicated to deal with in EF. You can write a method to encapsulate the two operations that should go together every time you delete a Result from a Student.
More info about Identifying relationships here.

Related

How to insert data in multiple tables if tables have relationship OneToMany, and #Column(unique = true)

I have two tables MAKES and MODELS. Between them relationship #ManyToOne.
Table MAKES:
#Column(unique = true)
private String make;
Table MODELS:
#Column(unique = true)
private String model;
When I insert schema car:
makes.setMake("Porsche");
models.setModel("911");
em.persist(makes);
em.persist(models);
Data is added, but if Porsche exist in MAKES table an exception is returned: ... Duplicate entry 'Porsche' for key ....
This constraint violation error is supposed to happen to prevent you from accidentally doing what you are doing here - inserting two separate Make instances that both have the Make column value of "Porsche". If you need to have multiple Makes with the value "Porsche", you need to relax the constraint to allow duplicates.
What seems more likely is this is intended, and you have an existing Make that you want to associate to or under a new Model. Read in the existing make from the DB and use that managed instance within your EntityManager context instead of trying to persist a new Make instance.
Ie
Query q = em.createQuery("select m from Make m where m.make = 'Porsche'");
Make Porsche = q.getSingleResult();
models.setModel("911");
models.setMake(Porsche);
em.persist(models);
you must save two table in two Transaction if you want one Transaction before sava Make table must check unique row after that save it. when in one Transaction create one exception the Transaction reverse.

How to get the Scope_identity value for the parent record using VS19 with bound datasets

I have two tables in MSSQL which are related tbl1.PK tbl2.PK, tbl2FK(_tbl1PK)
I have created a dataset in Visual Studio and they show up with the relation
when I drop the tables as datagrids onto a form I get the parentDG and childDG.
VS adds in the binding navigator which adds the save procedure
tbl1.bindingsource.endedit
tableadaptermanager.updateall
When I add data to the parentDG and press save the data gets saved to the DB.
When I add a new parent and then add a new child details and press save I get
System.Data.SqlClient.SqlException: 'The INSERT statement conflicted with the FOREIGN KEY constraint "FK_tblChild_tblParent". The conflict occurred in database "xxxxx", table "dbo.tblParent", column 'PK'.
I have tried updating the parentTableadapter and then ds.acceptchanges but I can not get the new child row to update.
I understand why but my questions are:
isn't the VS IDE supposed to handle this?
if isn't for me so I presume I need to get the new tbl1PK (scope_identity).
I can see in the dataset code the insert command:
Me._adapter.InsertCommand.CommandText = "INSERT INTO [] FROM tbl1 WHERE (PK= SCOPE_IDENTITY())"
BUT I cannot for the life of me see how to get this value.
I have a lot of tables with a lot of columns which is why I want/need to use the power of the IDE to populate and bind my controls and so I really do not want to go down the route of manually creating my datasets.
I have searched and searched on this and can't find anything that speaks to how you do this using VS auto generated code.
thanks
John
I just tested and the addition of the query in the InsertCommand happened automatically so you must not have done something properly. Here's EXACTLY what I did:
Created a new database named Test on my local default SQL Server instance via SSMS.
Added a table named Parent with columns ParentId (int, PK, identity) and ParentName (varchar).
Added a table named Child with columns ChildId (int, PK, identity), ParentId (int) and ChildName (varchar).
Created a foreign key in the Child table to the ParentId column from the ParentId column in the Parent table, setting the Update Rule to Cascade.
Created a new VB Windows Forms application project.
Added a new Data Source via the Data Sources window for the Test database.
Opened the TestDataSet from the Solution Explorer in the DataSet designer.
Selected the DataRelation between the two DataTables.
In the Properties window, clicked Edit Relation.
Checked 'Both Relation and Foreign Key Constraint', when Update Rule changed automatically to Cascade.
At this point, but even after step 7, I was able to select the ParentTableAdapter in the designer, expand the InsertCommand and view the CommandText to see this:
INSERT INTO [dbo].[Parent] ([ParentName]) VALUES (#ParentName);
SELECT ParentId, ParentName FROM Parent WHERE (ParentId = SCOPE_IDENTITY())
If you don't see that, you can set it yourself. What happens now is that, when the InsertCommand is executed to insert a new record, that query immediately retrieves the data from that record back into the DataRow in your DataSet. That will update the ParentId column with the newly generated value and the Update Rule will cause that new value to cascade to any related DataRows in the Child DataTable, so you can just go ahead and insert them without worry.

NHibernate throwing SQL CE Error 25026

I am using NHibernate with a SQL CE desktop database, and I'm getting an odd error when I try to do an update. SQL CE is throwing Error 25026: "A foreign key value cannot be inserted because a corresponding primary key value does not exist."
The exception occurs when performing a cascading update of a collection property of an entity object. The entity object is an Owner, and the collection property is Projects (IList), the projects for a particular Owner. In my database, the primary key of the Owners table is a three-character string (the owner's initials), with a corresponding foreign key in the Projects table.
Here's why I am puzzled: NHibernate can fetch all of the records for a particular owner (for example, "DCV"). And in my code, I can add a new Project object to Owner.Projects with no problem. I take the owner ID value directly from the Owner object fetched from the database, so I know the primary key exists in the Owners table. But when I do an ISession.SaveOrUpdate() on my Owner object, I get the foreign key error described above.
Am I dealing with some idiosyncracy of NHibernate, or some mundane error in my code or mappings? Any thoughts that would help me troubleshoot this problem greatly appreciated!
David Veeneman
Foresight Systems
I found the answer. It has to do with how NHibernate handles one-to-many associations. From the NHibernate Documentation, Sec. 6.4, One-To-Many Associations:
Very Important Note: If the
column of a association
is declared NOT NULL, NHibernate may
cause constraint violations when it
creates or updates the association. To
prevent this problem, you must use a
bidirectional association with the
many valued end (the set or bag)
marked as inverse="true". See the
discussion of bidirectional
associations later in this chapter.
If you are having this problem, remove the foreign key constraint temporarily and run your code, outputting NHibernate's SQL to the console. You will see that NHibernate first inserts the new record without the foreign key, then calls up the record, then inserts the foreign key into the record. The first operation is what generates the foreign key error.
The solution, as the NHibernate documentation points out, is to make the relation bidirectional.

How to delete child object in NHibernate?

I have a parent object which has a one to many relationship with an IList of child objects. What is the best way to delete the child objects? I am not deleting the parent. My parent object contains an IList of child objects. Here is the mapping for the one to many relationship:
<bag name="Tiers" cascade="all">
<key column="mismatch_id_no" />
<one-to-many class="TGR_BL.PromoTier,TGR_BL"/>
</bag>
If I try to remove all objects from the collection using clear(), then call SaveOrUpdate(), I get this exception:
System.Data.SqlClient.SqlException: Cannot insert the value NULL into column
If I try to delete the child objects individually then remove them from the parent, I get an exception:
deleted object would be re-saved by cascade
This is my first time dealing with deleting child objects in NHibernate. What am I doing wrong?
edit: Just to clarify - I'm NOT trying to delete the parent object, just the child objects. I have the relationship set up as a one to many on the parent. Do I also need to create a many-to-one relationship on the child object mapping?
You are getting the first error because, when you remove the items from the collection, NHibernate's default mode of operation is to simply break the association. In the database, NHibernate tries to set the foreign key column on the child row to null. Since you do not allow nulls in that column, SQL Server raises the error. Clearing the collection will not necessarily delete the child object, but one way to do so is to set cascade=all-delete-orphan. This informs NHibernate that it should delete the newly orphaned rows instead of setting the foreign key column.
You are getting the second error because when you call SaveOrUpdate NHibernate first deletes all of the child objects. Then, because neither relationship is marked as inverse, NHibernate also tries to set the foreign key column in your child table to null. Since the rows have already been deleted, you receive the second error. You need to set inverse=true on one side of your relationship to fix this. This is usually done on the one (primary key or parent) side. If you do not do this, NHibernate will make the appropriate updates for each side of the relationship. Unfortunately, running two updates is not the appropriate thing to do.
You should always mark one side of your relationships as the inverse side. Depending on how you code, you may or may not need to use cascading. If you want to take advantage of one shot deletes as you are trying to do using Clear(), you need to define your cascade.
Acording to Chuck's answer, I've resolved my problem by adding Inverse = true in parent side mapping:
Message has many MessageSentTo:
[HasMany(typeof(MessageSentTo), Cascade = ManyRelationCascadeEnum.AllDeleteOrphan, Inverse = true)]
public IList<MessageSentTo> MessageSendTos
{
get { return m_MessageSendTo; }
set { m_MessageSendTo = value; }
}
I am using Castle ActiveRecord. Thank you Chuck.
Try using merge() instead of saveOrUpdate(). Also, make sure your cascade is set to all-delete-orphan and that your parent-child relationship is invertible (inverse=true on the parent and then a field in the child that is the parent-id with not-null=true).
In our example we have categories with many products where a product is not nullable.
You can work around the problem by deleting the product and removing it from the parent's collection before the flush but we're still looking for a better solution to this.
product = pRepo.GetByID(newProduct.ProductID);
product.Category.Products.Remove(product);
pRepo.Delete(product);
Hope it helps anyway
Change cascade attribute value from "all" to "all-delete-orphan".
set Not-Null = true in your mapping on the column causing the issue. I'm not sure of the exact syntax though (sorry).

Association end is not mapped in ADO entity framework

I am just starting out with ADO.net Entity Framework I have mapped two tables together and receive the following error:
Error 1 Error 11010: Association End 'OperatorAccess' is not mapped. E:\Visual Studio\projects\Brandi II\Brandi II\Hospitals.edmx 390 11 Brandi II
Not sure what it is I am doing wrong.
I believe I can add some more clarity to the issue (learning as I go):
When I look at the Mapping details and look at the association, the column for operatoraccess table (from above) is blank and the drop down only includes field from the linked table.
The Entity Framework designer is terrible - I've had the same problem many times (and your problem too, Craig):
This happens when you have a many-to-one association which is improperly setup. They could very easily fix the designer to make this process simple; but instead, we have to put up with this crap.
To fix:
Click on the association, and go to the mapping details view.
Under association, click on Maps to <tablename>. Choose the table(s) which make up the many side of the relationship (ie. the table(s) which make up the *-side of the association in the designer)
Under Column, choose the table-columns which map to each entity-side Property. You get this error when one of those entries are blank.
I had the exact same problem and this is what I did to fix it.
Make sure you have an Entity Key set in your designer on the tables your making an association with. Also check that StoreGeneratedPattern is set to Identity for that Entity Key.
There's not a lot of information in your question, but, generally speaking, this means that there is an incompletely defined association. It could be that you have tried to map one table with a foreign key to another table, but have not mapped that other table. You can also get this error when you try to do table per type inheritance without carefully following the steps for implementing that feature.
Not sure of the answer, but I've just posted a similar question, which may at least help clarify the issue you are experiencing.
Defining an Entity Framework 1:1 association
I had to go back into the database itself and clarify the foreign key relationship
I had this problem in the case where I was creating both many to 0..1 and 0..1 to 0..1 associations. One entity needed associations to multiple tables, and that entity did not have foreign keys defined for those tables.
I had to do the table mappings step that is given in the accepted answer, but note that it wasn't only for many to many associations; it applied to all the types of associations I added for this entity.
In the Mapping Details view, I had to select the entity with the non-foreign key ID columns to the various tables. This is not always the "many" side of the relationship. Only there was I able to map the related entity property to the appropriate property in the original entity. Selecting the "destination" entity would not allow me to select the properties that I needed to, and the error would still exist.
So in short, I had to map using the table related to the entity that had the "non-foreign key" ID fields corresponding to the various entities' (and their tables') primary keys that I needed to associate.
Entity A
various other properties...
Id
ContactId
OrderId
etc.
Contact entity
Id
FirstName
LastName
etc.
In the mapping details, I selected Entity A's table. It then showed both ends of the association. I mapped its Entity A's Id property to its table's actual ID column (they had different names). I then mapped the Contact entity's Id field to the ContactId field on the A entity.
Simply select the many relationship table (*) from the Association>Edit Mapping & select the appropriate relationship