I have got another problem saving an m:n relation
The relation table is not getting the autogenerated key values of the Table A and Table B
Do you know how to deal with this?
I tryed saving the entity A and then entity B before making the TableAB relation and saving the middle element but it is not working.
If I use something like the code below, th the relation table will get null keys for the table A and B (relation table has a unique autogenerated key too.
// C#
DepartmentEmployees newDepEmp = new DepartmentEmployees();
newDepEmp.Employee = employee;
newDepEmp.Department = department;
// the 3 entities are now linked. We can now save recursively any of the three (doesn't matter)
// to save the relation in the database.
adapter.SaveEntity(employee);
And does not work, so what I tryed to do was to save employee and department before and refetching them, but still not working.
I am using firebird and adapter. The keys are autogenerated by a trigger and in a helpdesk question I got the help and could fix a Savecollection probem in a datagrid by reloading the Entitycollection after saving (because I can not drop the triggers).
[--- Updated: 17-11-2006 14:31:27 by user ---]
I am using adapter and a firebird database on .Net 2.0 using Winforms.
I am loading an editable grid and I put a SaveButton, I am using the adapter.SaveEntityCollection and passing the collection of objects, however I am getting this error:
"The entity is out of sync with its data in the database. Refetch this entity before using this in-memory instance."
What I use to save is the following code
private void btnSave_Click(object sender, EventArgs e)
{
UnloadGrid();
int empresasGrabadas = adapter.SaveEntityCollection(_empresasCollection,true,true);
MessageBox.Show(empresasGrabadas.ToString() + "saved elements");
LoadGrid();
}
public void LoadGrid()
{
adapter.FetchEntityCollection(_empresasCollection, null);
}
private void UnloadGrid()
{
this.gridControl1.DataSource = null;
}
I just want to know if this is the recomended way to do a grid save and why it may be throwing an error.
Solution:
It's not really more inefficient, as you now avoid a select statement for every inserted instance and do it in one select afterwards, so it's not that big of a deal performance wise.
The Firebird DQE doesn't have a feature build in to work around the insert triggers unfortunately.
[--- Updated: 20-11-2006 9:58:59 : Frans Bouma ---]
[--- Updated: 18-11-2006 11:50:17 : Frans Bouma ---]
Saved entities aren't reloaded after the save action unless you specify that. This is done to prevent unnecessary data load if you don't need the entities anymore. They are marked 'out-of-sync' to signal that the entity in the db is newer and perhaps has different values (due to triggers, default constraints etc.) and before you can access the data again the entity has to be reloaded
However you do specify true to refetch the entities after the save.
So could you test this for me:
- what is succeeded after the save call in SaveChanges?
- after the save call in SaveChanges, if you loop through the entities and check: entity.Fields.State, are there entities with the state EntityState.OutOfSync? If so, are there entities with this state BEFORE the save call in SaveChanges?
Reasons why refetch fails
There are a couple of reasons why a refetch fails. One of them is that a trigger updated the PK as well. Or that the PK wasn't inserted. The refetch is tried with the PK value known in the entity.
With firebird databases it's often the case that people define a trigger to insert the new PK value into a row. If you've defined in the llblgen pro designer that that entity also has a sequenced PK, you'll get this error. The reason is this:
- llblgen pro inserts a new entity, using the sequence / generator it inserts for the PK the value 1, this is the value stored in the entity as the PK value.
- the trigger inserts the next value in the entity and that's the value 2 as that's the first new value for the sequence
- llblgen pro tries to load the entity again, but that fails, as the entity has now the pk value 2, while the entity has the pk value 1.
To solve this: drop the trigger.
[--- Updated: 23-11-2006 7:37:30 by user ---]
Thank you very much for your help. I understand now why it was not working properly. I am making a system using databases from third party systems so I can not change their design. So what I am doing is to regenerate the collection after saving the changes.
It is working ok now, but I would like to know your opinion about it, I know I am loosing eficiency but I dont know if there may be another solution if I can not drop the triggers....
Llblgen is Great !!
I am using this now:
private void SaveChanges()
{
UnbindGrid();
DataAccessAdapter adapter = new DataAccessAdapter();
int succeeded = adapter.SaveEntityCollection(_paisCollection, true,false);
adapter.CloseConnection();
// Regenerate collection to avoid Synck problem with Firebird
_paisCollection.Dispose();
GenerateCollection();
BindGrid();
if (succeeded > 0)
{
MessageBox.Show("Cambios guardados exitosamente", "Guardar cambios", MessageBoxButtons.OK, MessageBoxIcon.Information);
btnGuardaCambios.Enabled = false;
}
else
{
MessageBox.Show(this, "No se pudieron guardar los cambios", "Save result", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
private void GenerateCollection()
{
WxSysPaisEntityFactory pais = new WxSysPaisEntityFactory();
_paisCollection = new EntityCollection(pais);
_paisCollection.ListChanged += new ListChangedEventHandler(_paisCollection_ListChanged);
}
private void BindGrid()
{
DataAccessAdapter adapter = new DataAccessAdapter();
adapter.FetchEntityCollection(_paisCollection, null);
adapter.CloseConnection();
paisSource.DataSource = _paisCollection.DefaultView;
}
private void _paisCollection_ListChanged(object sender, ListChangedEventArgs e)
{
this.btnGuardaCambios.Enabled = true;
}
private void btnGuardaCambios_Click(object sender, EventArgs e)
{
SaveChanges();
}