Entity Framework 6 Primary Key configuration issue on save of Entities - entity-framework

I'm trying to save few entities with this code:
this.UserService.Users.Add(eUser);
if (SelectedRewindItems != null && SelectedRewindItems.Count > 0)
{
foreach (var ug in SelectedRewindItems)
{
HpmModel.Usergroup nUg = new HpmModel.Usergroup();
decimal numId;
var a = Decimal.TryParse(ug.Key.ToString(), out numId);
nUg.Groupid = numId;
nUg.Userid = eUser.Userid;
// eUser.Usergroups.Add(nUg);
this.UserService.Usergroups.Add(nUg);
}
}
var submitOp = this.UserService.SubmitChanges();
IsSuccess = true;
ActionMessageOnButtonSuccess = User.Fname + " " + User.Lname + " Added Successfully !!";
string message = null;
if (submitOp.EntitiesInError.Any())
{
message = string.Empty;
Entity entityInError = submitOp.EntitiesInError.First();
if (entityInError.EntityConflict != null)
{
EntityConflict conflict = entityInError.EntityConflict;
foreach (var cm in conflict.PropertyNames)
{
message += string.Format("{0}", cm);
}
}
else if (entityInError.ValidationErrors.Any())
{
message += "\r\n" + entityInError.ValidationErrors.First().ErrorMessage;
}
MessageBox.Show(message);
}
else
{
MessageBox.Show("Submit Done");
}
But I'm getting this error:
System.InvalidOperationException was unhandled by user code
HResult=-2146233079
Message=The changes to the database were committed successfully, but an error occurred while updating the object context. The ObjectContext might be in an inconsistent state.
Inner exception message: Saving or accepting changes failed because more than one entity of type 'HpmModel.Usergroup' have the same primary key value. Ensure that explicitly set primary key values are unique. Ensure that database-generated primary keys are configured correctly in the database and in the Entity Framework model. Use the Entity Designer for Database First/Model First configuration. Use the 'HasDatabaseGeneratedOption" fluent API or 'DatabaseGeneratedAttribute' for Code First configuration.
Source=EntityFramework
StackTrace:
at System.Data.Entity.Core.Objects.ObjectContext.SaveChangesToStore(SaveOptions options, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction)
at System.Data.Entity.Core.Objects.ObjectContext.<>c__DisplayClass2a.b__27()
at System.Data.Entity.Infrastructure.DefaultExecutionStrategy.Execute[TResult](Func1 operation)
at System.Data.Entity.Core.Objects.ObjectContext.SaveChangesInternal(SaveOptions options, Boolean executeInExistingTransaction)
at System.Data.Entity.Core.Objects.ObjectContext.SaveChanges(SaveOptions options)
at System.Data.Entity.Core.Objects.ObjectContext.SaveChanges()
at OpenRiaServices.DomainServices.EntityFramework.LinqToEntitiesDomainService1.InvokeSaveChanges(Boolean retryOnConflict) in c:\Code\Repos\openriaservices\OpenRiaServices.DomainServices.EntityFramework\Framework\LinqToEntitiesDomainService.cs:line 145
at OpenRiaServices.DomainServices.EntityFramework.LinqToEntitiesDomainService`1.PersistChangeSet() in c:\Code\Repos\openriaservices\OpenRiaServices.DomainServices.EntityFramework\Framework\LinqToEntitiesDomainService.cs:line 138
at OpenRiaServices.DomainServices.Server.DomainService.PersistChangeSetInternal()
at OpenRiaServices.DomainServices.Server.DomainService.Submit(ChangeSet changeSet)
InnerException: System.InvalidOperationException
HResult=-2146233079
Message=Saving or accepting changes failed because more than one entity of type 'HpmModel.Usergroup' have the same primary key value. Ensure that explicitly set primary key values are unique. Ensure that database-generated primary keys are configured correctly in the database and in the Entity Framework model. Use the Entity Designer for Database First/Model First configuration. Use the 'HasDatabaseGeneratedOption" fluent API or 'DatabaseGeneratedAttribute' for Code First configuration.
Source=EntityFramework
StackTrace:
at System.Data.Entity.Core.Objects.ObjectStateManager.FixupKey(EntityEntry entry)
at System.Data.Entity.Core.Objects.EntityEntry.AcceptChanges()
at System.Data.Entity.Core.Objects.ObjectContext.AcceptAllChanges()
at System.Data.Entity.Core.Objects.ObjectContext.SaveChangesToStore(SaveOptions options, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction)
InnerException:
When I checked the Database Entities got saved but still it is giving me this issues.
Is this because I'm trying save them after saving User & Then UserGroup entities separatly. or Child Entities should get saved with Parent Entities. I'm a beginner so facing challanges.

After wasting a lot of time, I came to know that I need to fix my EDMX file & Entity Code.
So I added in my entity:
[DatabaseGenerated( DatabaseGeneratedOption.Identity)]
In the SSDL file in my Users -> Usersgroup (1-M) Relationship
Usersgroup Id Node I Added:
StoreGeneratedPattern="Identity" [SSDL]
In CSDL:
ed:StoreGeneratedPattern="Identity"
In my code:
this.UserService.Users.Add(eUser);
if (SelectedRewindItems != null && SelectedRewindItems.Count > 0)
{
foreach (var ug in SelectedRewindItems)
{
HpmModel.Usergroup nUg = new HpmModel.Usergroup();
decimal numId;
var a = Decimal.TryParse(ug.Key.ToString(), out numId);
nUg.Groupid = numId;
nUg.Userid = eUser.Userid;
eUser.Usergroups.Add(nUg);
}
}
After applying these changes, SaveChanges() worked.
This blog post helped me.

Related

c# entity framework savechangesasync saves new record but returns 0

Entity Framework: 6.1.3.
I have a function that reads a simple table for a record and either updates it or first creates a new entity. Either way it then calls AddOrUpdate and SaveChangesAsync. This function has worked for quite some time without any apparent problem.
In my current situation, however, I'm getting a return value of 0 from SaveChangesAsync. I have a break point just before the save and verified that the record doesn't exist. I step through the code and, as expected, a new entity was created. The curious part is that the record is now in the table as desired. If I understand the documentation, 0 should indicate that nothing was written out.
I'm not using transactions for this operation. Other database operations including writes would have already occurred on the context prior to this function being called, however, they should all have been committed.
So how can I get a return of 0 and still have something written out?
Here is a slightly reduced code fragment:
var settings = OrganizationDb.Settings;
var setting = await settings.FirstOrDefaultAsync(x => x.KeyName == key).ConfigureAwait(false);
if (setting == null)
{
setting = new Setting()
{
KeyName = key,
};
}
setting.Value = value;
settings.AddOrUpdate(setting);
if (await OrganizationDb.SaveChangesAsync().ConfigureAwait(false) == 0)
{
//// error handling - record not written out.
}

Entity Framework 6.1.3 migration ignoring second context

We have two models, a Shared model and an Individual model, each with their own context. The Shared model includes a listing of all individual items along with various metadata. Each individual item has a foreign key back to this listing.
When running migrations to the Individual model we connect back to the Shared context during the "Seed" method to grab some of the listing's metadata for that item. There may be multiple instances of each type of context active at a time, so we sneak pieces of our desired Shared context's connection string into the Individual string by way of the "Application Name" attribute and dynamically generate the Shared one in code. It's a bit of a cheat, but it's worked fine for a very long time while using Entity Framework 6.0.1, however a recent upgrade to 6.1.3 seems to have broken this and I don't know why.
Here's some of our code:
public class IndividualConfiguration : DbMigrationsConfiguration<IndividualContext>
{
protected override void Seed(IndividualContext context)
{
var store = context.Stores.FirstOrDefault();
var storeListingId = store.StoreListingId;
var sharedContext = GetSharedContextFromIndividualContext(context);
var storeListing = sharedContext.StoreListings.FirstOrDefault(p => p.Id == storeListingId);
/* Use listing metadata for things... */
}
public SharedContext GetSharedContextFromIndividualContext(IndividualContext context)
{
var connString = context.Database.Connection.ConnectionString;
var builder = new SqlConnectionStringBuilder(connString);
/* Derive shared context info from the Application Name... */
builder.InitialCatalog = derivedCatalog;
builder.DataSource = derivedDataSource;
builder.ApplicationName = string.Empty;
return new SharedContext(builder.ConnectionString);
}
}
The migration command I enter into the Nuget Package Manager Console is:
update-database -configuration "IndividualConfiguration"
-ConnectionString "Data Source=localhost;Initial Catalog=IndividualDatabase; Integrated Security=True;
MultipleActiveResultSets=True; Application Name=SharedDatabase|localhost"
-ConnectionProviderName "System.Data.SqlClient" -force –verbose
Notice how "SharedDatabase|localhost" is used in the Application name. Those are the catalog and data source of the matching shared context. Looking at the results via the debugger, I can confirm that "builder.ConnectionString" has built the correct connection string, which would be:
"Data Source=localhost;Initial Catalog=SharedDatabase;Integrated Security=True;MultipleActiveResultSets=True;Application Name="
...and yet, when looking up the "StoredListings" DbSet from the returned sharedContext, the code errors out with "Invalid object name 'dbo.StoreListings'."
While troubleshooting this, I tried modifying the code that gets the SharedContext to see when things go wrong:
var ctx = new SharedContext(builder.ConnectionString);
var connBefore = ctx.Database.Connection.ConnectionString;
string latestMigration = ctx.Database.SqlQuery<string>("SELECT TOP 1 MigrationId FROM [__MigrationHistory] ORDER BY MigrationId DESC").FirstOrDefault();
var connAfter = ctx.Database.Connection.ConnectionString;
throw new Exception("CONN BEFORE: " + connBefore + Environment.NewLine + Environment.NewLine + "CONN AFTER : " + connAfter + Environment.NewLine + Environment.NewLine + "LAST MIGRATION: " + latestMigration);
...and ended up with:
CONN BEFORE: Data Source=localhost;Initial Catalog=SharedDatabase;Integrated Security=True;MultipleActiveResultSets=True;Application Name=
CONN AFTER : Data Source=localhost;Initial Catalog=IndividualDatabase; Integrated Security=True; MultipleActiveResultSets=True; Application Name=SharedDatabase|localhost
LAST MIGRATION: 201607081517538_LatestIndividualMigration
So for some reason, despite the shared context's connection string being correct, upon USING the connection it reverts back to the same individual string I used in the migration command.
Does anyone know why that second context is getting ignored? I can confirm that if I revert back to Entity Framework 6.0.1 everything starts working again, so I want to say that something changed from 6.0.1 to 6.1.3 that invalidates our code but I have no idea what that could be.

How to create a new primary key in Entity Framework, Database first?

I get a runtime exception from the below code. I think it is not creating a primary key (which is CustomerID, and int). I used the Wizard and I have experience from years ago with ADO.NET but this is my first project using Entity Framework 6.0 with DbContext. I generated the EDMX file using "database first", so an actual database is present. I don't think any other table has a foreign key association with this table that is mandatory, so I think (but am not sure) this runtime error is from a failure to create new primary key. This is either a very easy question or a hard one, so I will check later.
Paul
[OperationContract]
public void DoWork ()
{
try
{
using (var ctx = new MyEDMXdBExistingDatabase())
{
CUSTOMER myCustomerREALLYNEW = new CUSTOMER();
myCustomerREALLYNEW.LastName = "NeWLASTNAME";
myCustomerREALLYNEW.CustomerID = 0; //set primary key to zero and let entity framework create new one automagically? I think this works based on past experience, but it's not working now
ctx.CUSTOMERs.Add(myCustomerREALLYNEW);
ctx.SaveChanges(); //PROBLEM HERE If comment out this line no runtime error
}
}
catch (DbEntityValidationException ex1)
{
Debug.WriteLine(ex1.Message);
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
finally
{
}
}
I added the following code and it showed me that the new CUSTOMER was lacking a manditory, non-null field (the Address). Once I added myCustomerREALLYNEW.Address= "123 Street"; then the new record/object could be added.
Here is the code I added to catch the runtime exception, which I got off the net:
catch (DbEntityValidationException ex1)
{
Debug.WriteLine("!" + ex1.Message);
List<string> errorMessages = new List<string>();
foreach (DbEntityValidationResult validationResult in ex1.EntityValidationErrors)
{
string entityName = validationResult.Entry.Entity.GetType().Name;
foreach (DbValidationError error in validationResult.ValidationErrors)
{
errorMessages.Add(entityName + "." + error.PropertyName + ":" + errorMessages);
}
}
foreach (string s in errorMessages)
{
Debug.WriteLine(s);
}
}

delete and then insert object Entity framework

I have this method that delete object if exist and insert the new instance any way :
internal void SaveCarAccident(WcfContracts.BLObjects.Contract.Dtos.CarAccident DTOCarAccident)
{
using(var context = BLObjectsFactory.Create())
{
context.ContextOptions.ProxyCreationEnabled = false;
CarAccident NewCarAccident = ConvertToCarAccident(DTOCarAccident);
CarAccident carFromDB = context.CarAccident.FirstOrDefault(current => current.CarAccidentKey.Equals(NewCarAccident.CarAccidentKey));
if(carFromDB != null)
context.CarAccident.DeleteObject(carFromDB);
context.CarAccident.AddObject(NewCarAccident);
context.SaveChanges();
}
}
I sometimes get exception that the key already exist in table.
I wnted to know if the way I save the changes is a problem (saving after delete and insert and not after each one)
At the time I got the exception there were few clients that activate the method at the same time I blocked other clients from writing already, but is this may be the problem ?
Thanks
Eran

How to delete many-to-many relationship in Entity Framework without loading all of the data

Does anyone know how to delete many-to-many relationship in ADO.NET Entity Framework without having to load all of the data? In my case I have an entity Topic that has a property Subscriptions and I need to remove a single subscription. The code myTopic.Subscriptions.Remove(...) works but I need to load all subscriptions first (e.g. myTopic.Subscriptions.Load()) and I don't want to do that because there are lots (and I mean lots) of subscriptions.
You can Attach() a subscription then Remove() it - note, we're not using Add() here, just Attach, so effectively we're telling EF that we know the object is attached in the store, and asking it to behave as if that were true.
var db = new TopicDBEntities();
var topic = db.Topics.FirstOrDefault(x => x.TopicId == 1);
// Get the subscription you want to delete
var subscription = db.Subscriptions.FirstOrDefault(x => x.SubscriptionId == 2);
topic.Subscriptions.Attach(subscription); // Attach it (the ObjectContext now 'thinks' it belongs to the topic)
topic.Subscriptions.Remove(subscription); // Remove it
db.SaveChanges(); // Flush changes
This whole exchange, including getting the original topic from the database sends these 3 queries to the database:
SELECT TOP (1)
[Extent1].[TopicId] AS [TopicId],
[Extent1].[Description] AS [Description]
FROM [dbo].[Topic] AS [Extent1]
WHERE 1 = [Extent1].[TopicId]
SELECT TOP (1)
[Extent1].[SubscriptionId] AS [SubscriptionId],
[Extent1].[Description] AS [Description]
FROM [dbo].[Subscription] AS [Extent1]
WHERE 2 = [Extent1].[SubscriptionId]
exec sp_executesql N'delete [dbo].[TopicSubscriptions]
where (([TopicId] = #0) and ([SubscriptionId] = #1))',N'#0 int,#1 int',#0=1,#1=2
so it's not pulling all the subscriptions at any point.
This is how to delete without first loading any data. This works in EF5. Not sure about earlier versions.
var db = new TopicDBEntities();
var topic = new Topic { TopicId = 1 };
var subscription = new Subscription { SubscriptionId = 2};
topic.Subscriptions.Add(subscription);
// Attach the topic and subscription as unchanged
// so that they will not be added to the db
// but start tracking changes to the entities
db.Topics.Attach(topic);
// Remove the subscription
// EF will know that the subscription should be removed from the topic
topic.subscriptions.Remove(subscription);
// commit the changes
db.SaveChanges();
One way would be to have a stored proc that will delete your child records directly on the DB and include it in your EF model; then just call it from your DataContext.
Here is my example ...where i know the foreign keys and i don't want to do a db round trip.
I hope this helps someone...
Given:
[client]<--- many-to-many --->[Medication]
Client objClient = new Client() { pkClientID = pkClientID };
EntityKey entityKey = _commonContext.CreateEntityKey("Client", objClient);
objClient.EntityKey = entityKey;
_commonContext.Attach(objClient); //just load entity key ...no db round trip
Medication objMed = new Medication() { pkMedicationID = pkMedicationID };
EntityKey entityKeyMed = _commonContext.CreateEntityKey("Medication", objMed);
objMed.EntityKey = entityKeyMed;
_commonContext.Attach(objMed);
objClient.Medication.Attach(objMed);
objClient.Medication.Remove(objMed); //this deletes
_commonContext.SaveChanges();
If the foreign keys are set, referential integrity should do automatically via the DBMS itself when deleting the parent entities.
If you use code first, as far as I learned in a MVA tutorial, ON DELETE CASCADE is the default behavior set by EF6. If running DB first, you should alter your childtable(s)...
Here is the link: https://mva.microsoft.com/en-US/training-courses/implementing-entity-framework-with-mvc-8931?l=pjxcgEC3_7104984382
In the Video it's mentioned at 20:00 upwards and in the slide presentation it is said on page 14.
Cheers