What happens when saving objects using Entity Framework? - c#

Probably sounds like a silly question, but there is an aspect about it I would like to know:
I'm working with objects that have a Guid-property for PrimaryKeys, which gets auto-generated in the database. I am using Entity Framework, Code First. If I do a Console.WriteLine with this property before saving, the value is
00000000-0000-0000-0000-000000000000.
After using Add and SaveChanges in the context, if I do a Console.WriteLine again with the same property, I have a value:
615f98eb-4ced-422a-877f-b9caa6f2b91f
Obviously, the object in memory has been updates. But I want to know how. The Guid is genereated in the database, so what happens?
Does the Guid-property of the object simply get updated from the database through EF, or does EF reload the entire object into memory after saving it in the database?
I would like to know, because that will determine how I design NUnit-tests in the same project.

Your EF object is updated when you call domainContext.SaveChanges(); Your new Id is generated by SQL database and value of Id is return value from DB. It is same for data types int, Guid and similar.

EF does not only submit an Insert/Update statement, at the same time it does a get statement to retrieve the generated primary key. In fact it is one single query. Your entity's primary key is then updated with the retrieved one. No magic behind this.
That's also one of the reason why batch updates / inserts are not supported. Every entity has to be updated / inserted on its own.
This is a query that is being executed when inserting an entity with a computed int primary key:
insert [dbo].[TestTable]
([Name])
values ('myname' /* #0 */)
select [ID]
from [dbo].[TestTable]
where ##ROWCOUNT > 0
and [ID] = scope_identity()
As you can see, the insert statement is followed by a select statement retrieving the computed columns (in this case ID). If there are more computed columns they're all selected here.

Related

Add a Column to a Table via Linq or Triggers in SQL

The issue is like , I got two tables X & Y. When records are added to table X , columns should be added to the table Y in parallel.
http://prntscr.com/3owqfe <-- Provides a clear Idea.
I tried it with triggers , but seems like the triggers doesnt allow CREATE TABLE or ALTER TABLE. Anyway as I'm using Linq , Im trying to achieve that via Linq. Any suggestions ?
Edited: For the record the below trigger worked , but with an exception.
create trigger AddItemToCommon ON [SEP].[dbo].[ItemMaster]
FOR INSERT
AS BEGIN
declare #PAYID varchar(max)
select #PAYID = payCode from INSERTED
ALTER TABLE [SEP].[dbo].[CommonPayrollItems]
ADD sampleCol varchar(max)
END
Anyway it will only run once because , there cannot be more than 1 column of the same name. But if I can retrieve the row values grom ItemMaster table , it's still possible with triggers. Which I tried to replace sampleCol with #PAYID which results in Syntax error.
Linq does not have functionality to create or alter tables. You could however use the underlying connection of your Linq Datacontext to execute any SQL statement:
DataContext.ExecuteCommand(...)
And use that to run your alter table statement. This will not update your Linq model of that table though.
If you plan to do this at runtime, you might want to reconsider your data model and create a third table (eg. STable2Extended) that contains a foreign key to both STable and STable2 combined with the applicable value for that column.
You could then add the STable2Extended to the datamodel and query it easily when you need the extended properties on STable2 without dynamically modifying tables.

How to insert to table with one-to-one relationship via dataset

I use asp.net 4 and DataSets for accessing the database. There are two tables with one-to-one relationship in the database. It means that both tables have the same column as a primary key (say Id), and one of tables has #identity on this column set.
So in general if we want to insert, we insert first into the first table, than insert into the second table with id.table2 = id of the corresponding record in table1.
I can imagine how to achieve this using stored procedure (we would insert into the first table and have id as an out parameter and then insert into the second table using this id, btw all inside one transaction).
But is there a way to do it without using a stored procedure? May be DataSets \ DataAdapters have such functionality built in?
Would appreciate any help.
Today it is so quiet here... Ok if anybody is also looking for such a solution, I've found a way to do it.
So our main problem is to get the id of the newly created record in the first table. If we're able to do that, after that we simply supply it to the next method which creates a corresponding record in the second table.
I used a DataSet Designer in order to enjoy the code autogeneration feature of the VS. Let's call the first table TripSets. In DataSet Designer right click on the TripSetsTableAdapter, then Properties. Expand InsertCommand properties group. Here we need to do two things.
First we add a new parameter into the collection of parameters using the Parameters Collection Editor. Set ParameterName = #TripId, DbType = Int32 (or whatever you need), Direction = Output.
Second we modify the CommandText (using Query Builder for convenience). Add to the end of the command another one after a semicolon like that:
(...);
SELECT #TripId = SCOPE_IDENTITY()
So you will get something like this statement:
INSERT INTO TripSets
(Date, UserId)
VALUES
(#Date,#UserId);
SELECT #TripId = SCOPE_IDENTITY()
Perhaps you will get a parser error warning, but you can just ignore it. Having this configured now we are able to use in our Business logic code as follows:
int tripId;
int result = tripSetsTableAdapter.Insert(tripDate, userId, out tripId);
// Here comes the insert method into the second table
tripSetTripSearchTableAdapter.Insert(tripId, amountPersons);
Probably you will want to synchronize this operations somehow (e.g. using TransactionScope) but it is completely up to you.

Scope_Identity() in Entity Framework

What is the equal code in EntityFramework to this sql code?
select Scope_Identity()
I want to get the id of the last record that i have inserted to database in EF.
You must ensure that your key property is mapped with StoreGeneratedPattern.Identity (here you can find some more about this setting). This should be used as default when generating the model from MS SQL database where the key column is defined with IDENTITY. After that it is enough to call SaveChanges on the context and the key property will be automatically filled for you.

C# DataTable and PK

I'm having such a problem: got dataset with a table(s). Say, we have already several records in a table which has a primary key (autoincrement). Basically, program works fine until I insert a new row. Even I use method AcceptChanges or Update, the new row is commited but it existing datatable object lacks the newest primary key value which I need for furhter processing. Is the only method to reload all the table from database again or there is a better way for it?
Thanks,
Ray
You should add ';select SCOPE_IDENTITY()' to the end of your insert sql statement attached to your data adapter. That will read back the last inserted value generated by autoincrement and update your dataset.
I.e, your insert sql should resemble this:
insert into sometable(column1,column2) values(#column1,#column2); select * from sometable where primarykeycolumn=scope_identity()
Your existing dataset will then contain the primary keys when dataadaper.Update(dataset) returns.
If you have a connection object you could use
int = (int)conn.executeScalar("SELECT ##IDENTITY")
Modified by what datatype your primary key is.
This has to be done directly before any other operations as a new insert will replace the stored value in ##IDENTIY

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