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

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.

Related

Replicate Entire Row In Entity Framework Core

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

Similar Columns Relation in Entity Framework

I use Entity Framework 4 on C# Winforms.
I have a SQL Server database with 2 tables like this:
Users table:
UserId (int) (PK)
UserName
Products table:
ProductId (int)(PK)
ProductTitle
UserId1 (int) (foreign key referencing `UserId` in `Users` table)
UserId2 (int) (foreign key referencing `UserId` in `Users` table)
I am modeling SQL Server database in my C# project with Entity Framework (including foreign key columns in model).
Then I get records with this code:
Entities dbEnteties = new Entities();
dbEnteties.ContextOptions.LazyLoadingEnabled = false;
var dbe = dbEnteties.Products.Include("Users");
var result = dbe.ToList();
When I get records from database I see that the UserId1 field has data but UserId2 field is Null.
What's wrong with my C# code? And how can I solve this problem?!
It's perfectly okay for you to have two foreign keys in the Products table pointing to the Users table. I do this all the time, and your reason for doing it is fine.
Since you have turned Lazy Loading off, you need to explicitly ".Include" the navigation properties if you want the query to automatically load them. You're going to have to figure out what the names are for the navigation properties that Entity Framework created automatically for you. I'm assuming you are using the "Database First" model. If that's the case, then double click on your .EDMX file and look at the Products table. You should see a section there called "Navigation Properties". They might be called "User" and "User1". If this is the case, then you need to do the following. Since you have two separate relationships between the tables, you will need two separate ".Include" statements:
dbEnteties.Products.Include(product => product.User);
dbEnteties.Products.Include(product => product.User1);
(Make sure to include using System.Data.Entity; at the very top of your file, otherwise the lambda syntax will not work.)

Edmx not returning auto incremented value

I am using Oracle 11g database. Many tables created in database and indexer applied on Primary key. After that i used Entity Framework 5.0 to connect with database.
The issue is that , when i am saving any record in table, it doesn't send Primary key which is auto incremented value.
public HttpResponseMessage PostCategory(TBLCATEGORY tblcategory)
{
if (ModelState.IsValid)
{
db.TBLCATEGORies.Add(tblcategory);
db.SaveChanges();
int32 ID=tblcategory.ID;
return ID;
}
}
it returns ID =0;
And one more thing, while creating any column Integer in oracle, it is showing decimal in Entity Framework.
I am assuming that you have defined a sequence and a trigger in the Oracle database that does the auto increment of the ID column, so only the object in the EF model is not updated, but the actual entry in the database has the correct incremented ID value, right?
Then the problem is that the edmx model does not know that the column is actually an ID column where the value is generated in the database. You have to manually edit the edmx model. The respective column entry in the SSDL section must have the StoreGeneratedPattern property set to "Identity". This tells the model to check again the database after inserting to look up the generated ID value. However, everytime you update the model from the database, your manual changes are lost.
I have written a short blog post about it: http://blog.aitgmbh.de/2014/06/02/patch-for-entity-framework-models-based-on-oracle-databases/
And I have created a NuGet package that does everything for you whenever you build the project: http://bit.ly/1hbxIsO
This way, even after updating your edmx model, the Identity property is added again to the specified ID columns.
Could you check the following articles:
problem description:
http://connect.microsoft.com/VisualStudio/feedback/details/505178/storegeneratedpattern-property-in-ado-net-entity-model-designer-sets-cdsl-annotation-but-not-ssdl-attribute
solution to the problem:
http://visualstudiogallery.msdn.microsoft.com/a63745c0-a781-48fa-a7d2-573ee80b5d7e

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.

Categories

Resources