Replicate Entire Row In Entity Framework Core - c#

I am trying to retrieve a row from database , changing certain columns value in it and adding it as new row (Entity Framework Core),
But it is giving me error
Cannot insert explicit value for identity column in table 'Audit_Schedules' when IDENTITY_INSERT is set to OFF.
This table have a Primary Key "ScheduleId"
Below is my Code
AuditSchedules _schedules = new AuditSchedules();
using (var ctx = new QuestionnaireEntities(_configuration))
{
_schedules = ctx.AuditSchedules.Where(x => x.ScheduleId == model.ScheduleID).SingleOrDefault();
_schedules.StaffId = model.TransferedAuditorCode;
_schedules.StaffName = model.TransferedAuditorName;
_schedules.FromDate = _schedules.ToDate = Convert.ToDateTime(model.TransferedScheduleDate);
ctx.AuditSchedules.Add(_schedules);
ctx.SaveChanges();
_subschedules = ctx.AuditSubSchedule.Where(x => x.SubScheduleId == model.SubScheduleID).SingleOrDefault();
_subschedules.IsHoliDay = "Y";
_subschedules.HolidayType = model.HolidayType;
_subschedules.TransferedScheduleId = _schedules.ScheduleId.ToString();
ctx.AuditSubSchedule.Update(_subschedules);
ctx.SaveChanges();
}
Error Comes In
ctx.AuditSchedules.Add(_schedules);
First I thought its conflicting in value of Schedule_ID and not able to add duplicate Primary Key , But Schedule_ID is auto generated field so this issue should not occur
I also tried setting it to different value
_schedules.ScheduleId = 0;
but it does not insert .
How Can I replicate a row with few changes in it (want to add a new row but modified values)

EF Core behavior with auto generated values on insert is different than EF6.
First, the property must have default value (0) in order to be auto generated. This allows identity inserts which was not possible in EF6.
Second, the entity being added should not be already tracked by the context, because otherwise the context keeps internally some information that the entity key has been set and will include the value (even 0) in the generated INSERT command, which in turn causes the exception you are getting.
To achieve the goal, before calling the Add method:
First make sure the entity is not tracked by either using No-tracking query when obtaining it
_schedules = ctx.AuditSchedules
.AsNoTracking() // <--
.Where(x => x.ScheduleId == model.ScheduleID)
.SingleOrDefault();
or explicitly detaching it
ctx.Entry(_schedules).State = EntityState.Detached;
Then reset the PK
_schedules.ScheduleId = 0;
The do other modifications and finally call
ctx.AuditSchedules.Add(_schedules);
This will work for simple entities w/o navigation properties / FKs. For complex entity graph you should use no tracking query, and then work with it the same way as with detached entity graphs.

The error is simple, it is because you are adding the identity insert as a part of insert. If it is identity, it has to be auto generated. So either turn off before insert and then turn it on. Or make it auto generated.
This error will be the same if you try and insert the same data from sql server.
This is basically propagated from sql server.
If you do not want an ID to be database generated, then you should use the DatabaseGenerated attribute on your model, as in
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int ScheduleId {get;set;}
If you want the identity insert to be off you can try the technique here

Related

EF5 doesn't track Identity oracle field after insert and saveChanges()

So, I'm trying to get the Id of the inserted object using entity framework 5 and Oracle.ManagedDataAccess but it keeps returning 0 although it inserts correctly in db.
I use an ID column with a sequence and trigger in the Database.
*note: I use database first approach.
Here is the code:
var test_trans = new TEST_TRANSACTION101() {
NAME = tran.Name,
TEST_NUMBER =tran.Test_Number
};
_context.TEST_TRANSACTION101.Add(test_trans);
_context.SaveChanges();
int id = test_trans.ID; // here it should retrieve the id from db
I used [DatabaseGenerated(DatabaseGeneratedOption.Identity)
and many other solutions I found here nothing seems to work.
It seems that ef doesn't track my entity. Any help?!
After alot of search I've found that Entity Framework misGenerate my data model. So I had to open model designer and make property Id as Identity myself.

EF5: Conflict with the FOREIGN KEY constraint

I'm new to using entity framework. I'm using EF5 to insert new data.
I get the dreaded error:
The INSERT statement conflicted with the FOREIGN KEY constraint "FK_POSTransactionsKitMemberTaxRaw_POSTransactionsKitMemberSaleReturnRaw_KitMemberSaleReturnRowId".
I understand that to mean I don't have a row in [POSTransactionsKitMemberSaleReturnRaw]
with a primary key that matches the insert for table [POSTransactionsKitMemberTaxRaw].
I wanted EF to generate the primary keys for me and expected the missing row to have been generated automatically. Here's the code that's failing:
foreach (POSTransactionsKitMemberSaleReturnRaw posTransactionsKitMemberSaleReturnRaw in posTransactionsKitMemberRaw.POSTransactionsKitMemberSaleReturnRaws)
{
++KitMemberSaleReturnRowId;
// set temporary keys
posTransactionsKitMemberSaleReturnRaw.KitMemberSaleReturnRowId = KitMemberSaleReturnRowId;
posTransactionsKitMemberSaleReturnRaw.KitMemberRowId = KitMemberRowId;
repository.AddPOSTransactionsKitMemberSaleReturnRaw(posTransactionsKitMemberSaleReturnRaw);
foreach (POSTransactionsKitMemberTaxRaw posTransactionsKitMemberTaxRaw in posTransactionsKitMemberSaleReturnRaw.POSTransactionsKitMemberTaxRaws)
{
// set temporary keys
posTransactionsKitMemberTaxRaw.KitMemberTaxRowId = ++KitMemberTaxRowId;
posTransactionsKitMemberTaxRaw.KitMemberSaleReturnRowId = KitMemberSaleReturnRowId;
posTransactionsKitMemberTaxRaw.KitMemberKitMemberSaleReturnRowId = null;
repository.AddPOSTransactionsKitMemberTaxRaw(posTransactionsKitMemberTaxRaw);
}
}
I've validated that there are temporary primary key values in the POCO objects at run time. A sql trace of the activity shows the attempted insert value was a generated value (1439630) not the temporary value I set it to.
I've set the Auto detect changes flag off:
_context.Configuration.AutoDetectChangesEnabled = false;
The intent was to improve performance. Since this is a pure insert
there should be no way the database rows will change while I am trying to write them.
Any suggestions?

How to obtain the identity of an entity after calling SaveChanges() when the entity is mapped to stored procedures

We are using Entity Framework 4.0 and we have an entity that is mapped to stored procedures provided by our DBA. The Insert, Update, and Delete functions in the mapping details all have their own stored procedures.
When using entities that are mapped to tables I am able to add a new entity, call dataContext.SaveChanges(); and then the new entity I instantiated automatically has its ID property populated with the value from the identity column in the database.
How can this be accomplished when the entity is mapped to stored procedures? Does the INSERT stored procedure have to do something special and/or do I have to do something special on dataContext.SaveChanges();?
Example
Traditional way
var newCustomer = new Customer
{
Name = "Fred",
Age = 24
};
// newCustomer.Id is null
dataContext.Customers.Add(newCustomer);
dataContext.SaveChanges()
// newCustomer.Id is what database identity column was set to.
Mapped to stored procedures.
var newCustomer = new Customer
{
Name = "Fred",
Age = 24
};
// newCustomer.Id is null
dataContext.Customers.Add(newCustomer);
dataContext.SaveChanges()
// newCustomer.Id is null
If you are using Identity column in database make sure that your stored procedure contains:
SELECT Scope_Identity() AS Id
after calling INSERT
Also make sure that PK in your entity mode is correctly configured with StoreGeneratedPattern set to Identity (should be automatically if you used Update from database)
I believe your DB needs to use ##identity or insert with a NewID() and return the Identity/NewID value back to you via the stored procedure. You technically could select from the database for the record you inserted, but that is a very questionable way to do it as; you don't know if the records was inserted (unless the SP failed at .Net), you may not know if duplicated records exists, or even if the data was changed after the insert but before the select. When in doubt I always highly recommend talking to your DBA about the best approach to your specific needs based your DBAs design.
Updates:
If he returns you the PK value, you should be able to do a standard select from the table to populate the entity like from e in context.entities where e.pkcolumn = spkeyreturned select e.
If he returns you ALL the data back, and can guarantee the data won't change, you might be able to create a new entity, populate it will all the data and use the Attach method. I personally wouldn't do that, but it is an option. Attaching and Detaching Object in Entity Framework.

Entity Framework One-To-Many Insert - Foreign Key violation

I'm using Entity Framework for the first time and I'm trying to create a object with a collection (and I want all the objects in the collection to be created in database as well) but I'm having some foreign keys violations.
My sample tables:
table APPOINTMENTS: ID, VAR1, DATE_APPOINTMENT
table GUESTS: ID, APPOINTMENT_ID, USER_ID, VAR2, VAR3
My test code:
DomainService aux = new DomainService();
APPOINTMENTS appointment = new APPOINTMENTS();
appointment.VAR1 = "BLA";
appointment.DATE_APPOINTMENT = new DateTime();
//The user with id = 1 is already created in the database
appointment.GUESTS.Add(new GUESTS { USER_ID = 1, VAR2 = 1, VAR3 = "F" });
aux.InsertAppointment(appointment);
At DomainService I have:
public void InsertAppointment(APPOINTMENTS appointment)
{
using (var context = this.ObjectContext)
{
context.AddToAPPOINTMENTS(appointment);
context.SaveChanges();
}
}
But I'm getting this error:
{"ORA-02291: integrity constraint (FK_GUESTS_APPOINTMENTS) violated - parent key not found"}
What am I doing wrong?
UPDATE:
To create the ID's in the database, I am using a sequence for each table and a trigger before insert to get the next value.
When I create a single object, e.g. a appointment without guests, it inserts in the database and it generates the id.
The solution to this problem:
"The ID fields that are generated from sequences won't be handled
correctly. After saving the entities the ID's will be returned as 0.
I'll fix this by manually hacking the SSDL (open your .edmx file in a
text editor) with StoreGeneratedPattern="Identity" attributes on the
ID fields (lines 6 and 16). Note that designer may rip that change out
upon future modification.
While I suppose it's not absolutely necessary it might also be prudent
to modify some type metadata such as changing "number"s to "int"s in
your SSDL and "Decimal"s to "Int32"s in your CSDL where applicable.
Frequently these don't auto-generate with the desired values
especially with XE."
#http://www.chrisumbel.com/article/oracle_entity_framework_ef
As for me, the problem was solved simply by opening diagram .edmx and changing property StoreGeneratedPattern from None to Identity for each Primary Key in each table. After saving everything was fine.
I'm using VS 2012, Entity Framework 5 (6 is not supported yet), Oracle 11.2, last ODP.NET 12, .Net 4.5
In case of EF code first approach, if this error come
(ORA-02291: integrity constraint (FK_GUESTS_APPOINTMENTS) violated -
parent key not found)
In my case there are 2 tables which have Identity columns. So I just added
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
property to my model class just above the the column which is identity column in database and it solved my problem :)
Hope this help :)
I cant see where you are setting your Primary Key (the ID property of the appointment class). Are you using a key generator on the database side? If not this should be the problem.
You're inserting a record with a foreign key value that is not found in the parent table that constraint refers back to.

How does Entity Framework insert new values?

I have another question kind of relative to this but I'd like to separate them for clarity reasons.
I stumbled upon a problem where I couldn't insert a new row in a table because it only had one column and that column was incrementally increased and PK.
However, creating a new object of that Set in Entity Framework was no trouble at all.
var admin = new Administrator {};
context.Administrator.AddObject(admin);
context.SaveChanges();
int adminId = admin.adminId; //This would give me the new value
How does this work?
When you commit your changes, Entity Framework performs an INSERT into the table associated with the Administrator entity set, for each added entities.
As the PK is auto incremented in the database, EF knows that it doesn't need to provide it, but retreive it after the INSERT. It then updates the Administrator entity with it's now available (and database generated) PK.
It's classic Object relational Mapping job, I hope I understood your question?
Here is the exact SQL query sent by EF to do the Insert job.
insert [dbo].[Entities] default values
select [Id]
from [dbo].[Entities]
where ##ROWCOUNT > 0 and [Id] = scope_identity()
It inserts a default row in the table, then select the new row's Id.

Categories

Resources