Using EF4 /w SQL Server 2008.
The following code (against a table with a PK, defined as Int IDENTITY(1,1):
ctx.AddObject(GetEntitySetName(), newEntity);
ctx.SaveChanges();
The results when profiling SQL are the insert statement following by a lookup against the table I'm inserting into:
SELECT ID FROM Table
WHERE ID = ##ScopeIdentity AND ##RowCount > 0
Is there a way to prevent EntityFramework from retreiving the Identity seed? I don't need the ID back in my .Net code and under high volume situations it seems like a wasted operation.
Altenatively, is there a way to tell EF to change the way it performs this operation? The strategy used goes against recommendations made by Microsoft in this defect report:
http://connect.microsoft.com/SQL/feedback/ViewFeedback.aspx?FeedbackID=328811
You cannot change this behavior when using database generated keys (properties marked with StorgeGeneratedPattern.Identity). EF needs a real key value for inserted entity so the only way to avoid the query is to not using database generated keys at all and handling it yourselves in the application.
Related
We have a SQL Server 2008 R2 database with several tables and each table has a number of triggers. On one of the columns, we'll call this Person.Age we have a default value, so that if I don't explicitly supply a value it defaults to "18".
create table PERSON
(
id int IDENTITY(1,1) PRIMARY KEY,
age char(2) DEFAULT '18',
Name char(40),
);
I am using EntityFramework 4.0 (and have also tried 5.0) and Visual Studio 2010, to load and select from the database. Whenever I insert into the table using the following statement, it is inserting a row, but it isn't completing the default value:
var person = new Person
{
Name = "Peter"
};
using (var ctx = new MyEntities())
{
ctx.PERSON.AddObject(person);
ctx.SaveChanges();
}
This will result in a row with a Name of Peter, but the Age will be set to null - and not my default of 18.
When I refresh/load my EDMX file I can only seem to import simple tables and views and there doesn't appear to be an option for importing the properties - although I would have thought this was done by default? Any ideas why the default properties aren't firing?
Also, I have triggers defined in SQL Server so that when a new row is inserted into PERSON, an additional table gets updated. Again this works if I run the SQL direct against the database, but doesn't work if I execute through Visual Studio using EntityFramework.
Thanks,
EF will explicitly set the columns to values you passed. Since, when you created a Person entity, the value for age will be by default set to null EF will send a command in which it will set the column value to null. Set the default value in the ctor if you want to have the default value (otherwise the default value is null for reference properties and default(T) for value type properties (e.g. int)).
The EF designer brings all the columns from the database and create a model with entities that have properties coresponding to the values to the tables and columns it reversed engieneered. You can then go and tweak your model in the designer - for instance you can remove properties you don't want.
I don't know what "does not work" means for you in case of the triggers - it probably depends on your expectation. EF just sends a command to the database. So if you send the same Sql command as the EF sends it should "not work" in the same way. Having said that EF is database agnostic and is not aware of DB magic like triggers. Also the communication is one way only from EF to the DB. So, if you expect that the database notifies the EF about something then it will not work. There are no means for doing this.
Did you ever try to create a ASP.NET MVC Project with Firebird database...I try it, and is difficult..
My problem:
I have working Firebird provider for Visual Studio 2010.
I have correct database with all needed for increasing the id of the tables.
I have created ASP.NET MVC 3 project, with included database, like EDMX file, with entities.
When i try to insert a record into a table, there occurs a problem that says:
FirebirdSql.Data.Common.IscException: violation of PRIMARY or UNIQUE KEY constraint "PK_USERS" on table "USERS"
That means the id of the record that is created is not increased.
I have stored procedures that must generate new id.
My question is:
How to insert record in Firebird data table from ASP.NET?
In Firebird you need to use triggers in combination with sequences (generators) if you want to have auto-increment like behavior. Otherwise you need to make sure that you assign a unique id yourself.
To create the sequence:
CREATE SEQUENCE mytable_id_sq;
To create a trigger for assigning a unique i (on a table called mytable)
set term !! ;
CREATE TRIGGER T1_BI FOR mytable
ACTIVE BEFORE INSERT POSITION 0
AS
BEGIN
if (NEW.ID is NULL) then NEW.ID = NEXT VALUE FOR mytable_id_sq;
END!!
set term ; !!
This trigger will only assign a generated value if no ID is assigned in the INSERT statement.
See also:
section SEQUENCE (GENERATOR) in the Firebird 2.5 Language Reference and How to create an autoincrement column? (this link talks about generators, the old name of sequences in Firebird).
Your EDMX isn't probably generated properly. Either you have to set the StoreGeneratedPattern manually or use http://blog.cincura.net/230841-generated-primary-key-in-entity-framework-model-from-firebird/ .
I have a web application using EF4. I am somewhat new to EF and now trying to implement change Audit.I tried to do this by trapping the SavingChanges event of the Context Class as below
partial void OnContextCreated()
{
this.SavingChanges += new EventHandler(TicketContainer_SavingChanges);
}
So the event handler accesses the changed records by the following
this.ObjectStateManager.GetObjectStateEntries(
EntityState.Added | EntityState.Modified);
This works fine and I am creating column level audit for selected tables. Every table/entity has an ID field which is an identifier with columnName="ID". So in my audit routine I simply accesses data from column with name "Id" to get the ID of audited record.
The problem I face is during insert . The new record has no ID yet as it is an identity column in the database and is always 0.
One solution I can think of is using GUID for all Ids.But is there a way to implement this using standard int32 Identity Ids?
thanks
When we insert data through EF the identity column is not generted while insertion. To get the Id of Identity columns we have to insert the data first then only we can get the Id of coulmn.
please go through the below which might be helpful to you.
http://www.codeproject.com/KB/database/ImplAudingTrailUsingEFP1.aspx
I don't now how many entities you have but in our own implementation of audit tracking we created a specific audit entity for each entity so we could link them together trough navigational properties and let the database set the identity keys.
If you use inheritance for your audit entities it's quit easy to query them.
Hope this helps :)
Identity columns are not generated while insertion. Once data is inserted then only you can get identity column data in EF. So, you can try some work around by getting Id after insertion and then populating audit table with that Id.
I have the challenge of needing to audit data changes made by users of an MVC application.
Auditing creation and deletion of records is easy.
Updates is proving to be the problem.
I'm looking for a way to automate this, but the problem I have is that the application is using stored procedures to bring back EF "complex types".
These are then used to build a view model, and after postback, the controller receives a new view model built from the form values passed back from the view. Therefore the original values are no longer available.
Does anyone have any suggestions for a secure way to keep the original values so they can be compared with the updated values, so that changes can be stored?
(I appreciate I could go back to the database for these, but is not efficient, and I would have to retain all the parameters to remake the same call, and find a way to automate that part of the process).
Have you tried an Audit Trigger using the INSERTED and DELETED tables.
http://weblogs.asp.net/jgalloway/archive/2008/01/27/adding-simple-trigger-based-auditing-to-your-sql-server-database.aspx
OR
In your stored procedures for insert,delete,update you can make use FOR XML AUTO. To get the XML for the record and add it to an audit table.
http://www.a2zdotnet.com/View.aspx?Id=71
UPDATE A T-SQL example
BEGIN
-- these tables would be in your database
DECLARE #table TABLE(ID INT IDENTITY(1,1) PRIMARY KEY, STR VARCHAR(10), DT DATETIME)
DECLARE #audit_table TABLE(AuditXML XML, Type VARCHAR(10), Time DATETIME)
-- this is defined at the top of your stored procedure
DECLARE #temp_table TABLE(PK INT)
-- your stored procedure will add an OUTPUT to the temp table
INSERT INTO #table
OUTPUT inserted.ID INTO #temp_table
VALUES ('test1', GetDate()),
('test2', GetDate() + 2)
-- at the end of your stored procedure update your audit table
INSERT INTO #audit_table
VALUES(
(
SELECT *
FROM #table
WHERE ID IN (SELECT PK FROM #temp_table)
FOR XML AUTO
),
'INSERTION',
GETDATE()
)
-- your audit table will have the record data
SELECT * FROM #audit_table
END
In the example above you could make temp_table a clone of table (have all of the columns from table) and in your OUTPUT clause use INSERTED.* INTO #temp_table, this would avoid have to reselect the records before getting the FOR XML AUTO. Another note, for stored procedures that do DELETE you would use DELETED.* instead of INSERTED.* in your OUTPUT.
If using SQL Server I recommend that you look into Change Data Capture (CDC).
It's an out of the box solution for auditing changes to the underlying tables of your application and it's relatively straightforward to set up, so there is no need for a custom solution that you then have to maintain.
If you have any supporting applications for your site, they'll also be covered and it also has the benefit of auditing any changes made directly against the database, such as from a DBA running a script.
Since your asp.net application may be running under one particular account, you'll probably need to add additional tracking information to capture the user who made the change. Fortunately this is also relatively straightforward. The following Stack Overflow question covers an approach to this using the ObjectStateManager
I was lookging for this myself, found this, check out Tracker for EF
I want to update a single field in my table for a particular row. I am using Entity Framework 4 and Visual Studio 2010.
Options I can think of are:
Using a Stored Procedure
Direct connection to the database and using
sql statement
I am not aware of any more efficient method to perform this task.
[EDIT]
I would like to do the update in the same operation as the Get for that row, so that it is done in one DB call.
No need to complicate things. Just change the one property and SaveChanges. Unless you're doing something odd, that should only change the one column. Look at the SQL to verify.