EF7: deleted data from relationship table on context.SaveChanges() - c#

Forgive me for not knowing how to technically express the situation...
Main table, drop down table. Saving an Updated entity for main table (which holds FK for drop down table, deletes value for that record in the drop down table.
Why would changing a value in the main table, delete the value for the corresponding record in the drop down table?
save function
public void UpdateApplicationDetails(Application UpdatedApp)
{
AtlasContext updatecontext = new AtlasContext();
Application currAppRecord = _context.Apps.Where(a => a.Id == UpdatedApp.Id).Single();
currAppRecord = UpdatedApp;
updatecontext.Apps.Update(UpdatedApp);
updatecontext.SaveChanges();
}
Will update with necessary info if requested. Thanks for taking the time

Related

Entity Framework Core generating -ve integer values for Primary Key column on a table row add

I am using EF Core v2.2 for inserting and updating rows into a table.
While I am doing that, I am looping based on a list and trying to insert into the table. For the 1st row insert the code works as expected.
However from the second item in the list the row doesn't get inserted into the table.
When I debugged, I found out that after the _rmsContext.save() the 2nd inserts the primary key value for the table is generated as -9223372036854774802.
Here is my code
foreach (string account in accntList)
{
var crossBowAccounts = _cbContext.SomeTableRepository
.FindBy(ca => ca.AccountId == account &&
ca.ClientId == model.ClientId)
.FirstOrDefault();
AccountHistory accountHistory = new AccountHistory()
{
AccountId = account,
ClientId = model.ClientId,
UserId = userId,
ActionName = crossBowAccounts == null ? "Add" : "Edit"
};
_rmsContext.AccountHistoryRepository.Add(accountHistory);
_rmsContext.Save();
// Some more insert/update code for a table in a different context .
_rmsContext.Save();
}
Here model is being passed as an input to the method.
This is what I observed during debugging:
This is my table schema
Looks like you are hitting this issue here: https://github.com/dotnet/efcore/issues/6147
EF Core generates temporary IDs which are then replaced with the real IDs when SaveChanges is called
It's not exactly a bug and it has been changed again in 3.1.
So until the item is inserted, a negative and/or random number makes sense. You need to see why it's not inserted (the negative id is not the reason).
it is not bug, id is generated randomly before call SaveChanges method. If you do debug after SaveChanges, Id will be correct.

Entity Framework - Updating entity's few columns only

I need some more understanding of how Entity Framework works. I have implemented code which is running ok and doing the job.
But I need to know that it is the good way or not.
I have a table with 8 columns, say
Table1
Column1 (pk)
Column2, Column3, Column4, Column5, Column6, Column7, Column8
Now when I click a button, I need to insert (if new) or update (for existing record) first 6 columns.
And on the same button click event, as part of the same process, I will call a stored procedure (with a parameter of primary key id, Column1) that will fetch these 6 columns values in the stored procedure itself and will do some calculations based on six column values and return two new values which I need to update in Column7, Column8.
So, process will be:
New record: insert (six columns data), calculations (call stored procedure), update (last 2 column)
Existing record: update (six columns data), calculations (call stored procedure), update(last 2 column)
Now, for insert, I use
_dbContext.Table1.Add(entity);
_dbContext.SaveChanges();
For existing record update (of first 6 columns), I use
//code - Entity property values are updated with new ones
_dbContext.Table1.Attach(entity);
_dbContext.Entry(entity).State = EntityState.Modified;
_dbContext.SaveChanges();
For last update, Column7, Column8, I use
var entity = GetById(Id);
if (entity != null)
{
entity.Column7 = value1;
_dbContext.Entry(entity).Property(t => t.Column7).IsModified = true;
entity.Column8 = value2;
_dbContext.Entry(entity).Property(t => t.Column8).IsModified = true;
_dbContext.SaveChanges();
}
I am not sure why I need not to attach entity for last update. Is it due to I have called GetById method for same table just above that?
Without attaching entity how it updates columns? (if I attach entity it gives error saying already being tracked)
Also, I have to call GetById multiple times to get record for both updates (in existing record scenario). Any other solution for that?
for that you can use MapToModel method
here is example
//code - Entity property values are updated with new ones
var newEntity= new Entity
{
Id = p.Id, // the Id you want to update
Column1= "" // put value for column/s that you need to update
};
newEntity.MapToModel(oldEntity);
_dbContext.SaveChanges();
IMHO I don't think you need to specify IsModified for each property if you fetch through the Context.
EF Context will automatically track Entities unless you change the default behavior
EF knows which entities are changed after loading from the database,hence it will be only updated.
Assuming GetById is fetching the data from data-store.
var entity = GetById(Id);
if (entity != null)
{
entity.Column7 = value1;
entity.Column8 = value2;
_dbContext.SaveChanges();
}
Detect Changes
Similar Question

EF 6 Ghost/Random records added when saving

I am having a problem that is extremely strange to me. I am working with EF6 and am modifying records in the database and then saving them. HOWEVER, on variable objects that have a foreign key, even though it exists in the db, it is randomly adding a new record to the table.
Example:
So if I have a CRec table that has a foriegn key to the Rect table, when I modify the CRec variable and save it, it is adding another entry to the Rect table.
I would add code but all I am doing is
ctxAcct.Entry(crec).State = EntityState.Modified;
Any ideas would be appreicated!
Edit
Workflow: User logins --> Opens their CRec --> edits --> clicks save.
With this being EF codefirst MVC, the below method is called from the view. oCRec is filled with foreign key values. So I will have a VendorID and a VendorID_ID. VendorID_ID is essentially a foreignkey field to the Vendor table.
When I hit save changes it is randomly adding a duplicate VendorID_ID when I haven't even touched that field.
Public void UpdateCRec(CRec oCRec)
{
ctxAcct.Entry(oCRec).State = EntityState.Deleted;
ctxAcct.SaveChanges();
//here I am making some changes and doing some calculations with other fields in the database.
//Now, after changing field values in CRec I move to the save changes method.
ctxAcct.Entry(oCRec).State = EntityState.Modified;
ctxAcct.SaveChanges();
}

Using Linq to determine if a record does not exist in a list but does exist in a table

I am having trouble determining if a record exists in the database table but not in the updated records contained within a list. If the record does not exist within the updated list but does within the database table then that record needs to deleted.
I can query the table to determine if it has been modified and if the record does not exist in the database table then update it, but determining the opposite is proving a bit more tricky. Another constraint is that I need the outcome to be a bool value of exists = true and not exist = false so that i can than handle the deleting of the record appropriately.
I am doing this to determine if the record does not exist in the database table:
bool exists = db.table.Any(t => t.EntityID != list.EntityID)
But can not seem to manage the reverse.
The list and the database table have 1 to 1 mapping using Entity Framework.
If record exists in database but not in list then delete.
Looks like you've reversed the logic there. If you want to check for the existence of a particular record, the ID of which is stored in list.EntityID, it looks like this:
bool exists = db.table.Any(t => t.EntityID == list.EntityID);
If you have a list of entities and you want to find any records that exist in the database that don't exist in the list you can do this:
var extraitems = db.table.Where(t => !list.Select(l => l.EntityID).Contains(t.EntityID));
That will give you a list of entities you can pass to DeleteAllOnSubmit().
bool exists = db.table.Any(t => list.EntityID.Contains(t.EntityID))

EF 4.1 code first - How to update/delete many to many join table entries automatically

I have 2 entities, let's say, Trip and Activity. The relationship between them is many to many so a join table is created automatically by EF.
Entity Trip attributes:
-Id (PK) Generated by database
-Name
-Description
-Property1
-Property2
-Property3
Entity Activity attributes (this entity contains fixed records -read only-, no records are inserted here on performing inserts):
-Id (PK) Generated by database
-Name
-Description
-Cost
Join table contains 2 columns, that is, the IDs of the above entities, that are primary and foreign keys at the same time.
I have no problems inserting entries which automatically EF creates join table TripActivities and add entries successfully to it. Also entries are added successfully to entity Trip and it leaves unchanged entity Activity.
My problem is on updating entries, for example, - suppose user can modify information related to a trip from the GUI - so I take all the info from this GUI and I perform the following steps to update the existing trip:
Trip trip = Context.Trips.Find(id); // Search for the appropriate trip to update from Id
trip.Name = ObtainNameFromGUI();
trip.Description = ObtainDescriptionFromGUI();
trip.Property1 = ObtainProperty1FromGUI();
trip.Property2 = ObtainProperty2FromGUI();
trip.Property3 = ObtainProperty3FromGUI();
trip.Activities = new List<Activity>();
// From the GUI user selects from a checkbox list the activities associated to the trip
// So we read its Ids and from those ids we fetch from database the activities to obtain
// the info related to each activity selected in the GUI. This is all done inside the
// below method.
List<Activity> activities = this.ObtainActivitiesSelectedFromGUI();
// If no activites selected (=null) I want EF automatically deletes the entries in the
// joined table for this trip. And of course, if there are activities selected, EF
// should update the respectives entries in the joined table for this trip with the new
// ones.
if (activites != null)
{
activities.ForEach(a =>
{
trip.Activities.Add(a);
});
}
context.Trips.Add(trip);
context.SaveChanges();<br><br>
By doing this I want EF updates all the entities related (except Activity as it has fixed entries, must be kept unchanged), that is, Trip and the joined table automatically but it does not work: a new trip is created and more entries in the joined table (The only thing that is working is that entity Activity is kept unchanged as I want).
How to achieve this? I have spent a lot of hours trying to do this but without success...
Thanks in advance.
EDIT:
I have removed line:
context.Trips.Add(trip);
Now the results are:
-Entity Trip is correctly updated, no new records added which is Ok.
-Entity Activity is kept unchanged which is Ok.
-Join table: The old records for current trip being updated are not updated, instead new records are inserted for the current trip which is not correct.
I have used a different approach for similar scenario that I faced, which works well with Detached Entities. What I ended up was finding out which entities were added and which ones deleted by comparing GUI(detached entity) values to the database values. Here is the sample code that I have used. The entities in play are RelayConfig and StandardContact which have many to many relationship
public void Update(RelayConfig relayConfig, List<StandardContact> exposedContacts) {
RelayConfig dbRelayConfig = context.RelayConfigs.Include(r => r.StandardContacts)
.Where(r => r.Id == relayConfig.Id).SingleOrDefault();
context.Entry<RelayConfig> (dbRelayConfig).CurrentValues.SetValues(relayConfig);
List<StandardContact> addedExposedContacts =
exposedContacts.Where(c1 => !dbRelayConfig.StandardContacts.Any(c2 => c1.Id == c2.Id)).ToList();
List<StandardContact> deletedExposedContacts =
dbRelayConfig.StandardContacts.Where(c1 => !exposedContacts.Any(c2 => c2.Id == c1.Id)).ToList();
StandardContact dbExposedContact = null;
addedExposedContacts.ForEach(exposedContact => {
dbExposedContact = context.StandardContacts.SingleOrDefault(sc => sc.Id == exposedContact.Id);
dbRelayConfig.StandardContacts.Add(dbExposedContact);
});
deletedExposedContacts.ForEach(exposedContact => { dbRelayConfig.StandardContacts.Remove(exposedContact);});
You will use something like this. Assuming that you will get the related objects from the UI and just you are going to update the same in the database, some thing like the following will work.
context.Products.Attach(product);
context.ObjectStateManager.ChangeObjectState(product, System.Data.EntityState.Modified);
context.ObjectStateManager.ChangeObjectState(product.ProductDescription, System.Data.EntityState.Modified);
context.ObjectStateManager.ChangeObjectState(product.ProductModel, System.Data.EntityState.Modified);
context.SaveChanges();
As you may see here, we are setting the EntityState as Modified which hints EF to perform update for the related tables too.
Please post back your queries or any issues that you may encounter in this implementation.

Categories