Database Won't Update Using Savechanges Method on Entity - entity-framework

I am using the Entity Framework in a MVC Web API and I can't figure out why the changes aren't being saved to the database. I am using the following code:
[HttpPost]
public HttpResponseMessage PostPXE(PXE pxe)
{
var pxeRequestID =
from qsp in db.Queue_Server_Provision
.Where(a => a.Server_Name == pxe.Server_Name)
join isni in db.IaaS_Server_NIC_Information
.Where(a => a.MAC == pxe.Mac_Address)
on qsp.IaaS_ID equals isni.IaaS_Server_Information_IaaS_ID
select qsp.Request_ID;
var QSP = db.Queue_Server_Provision.Find(pxeRequestID.FirstOrDefault());
db.Queue_Server_Provision.Attach(QSP);
QSP.Provision_Status_Code = "240.9";
db.Entry(QSP).State = EntityState.Modified;
try
{
db.SaveChanges();
}
catch (DbUpdateConcurrencyException e)
{
return Request.CreateResponse(HttpStatusCode.NotFound, e.Message);
}
catch (Exception e)
{
return Request.CreateResponse(HttpStatusCode.NotFound, "error");
}
return Request.CreateResponse(HttpStatusCode.OK);
}
While debugging everything seems to work fine until I call the SaveChanges() method, at that point the Provision_Status_Code value reverts to what it was before being modified.
The following SQL is generated from the Entity Framework:
exec sp_executesql
N'update [dbo].[Queue_Server_Provision]
set [Server_Name] = #0,
[Environment_List_ID] = #1,
[Operating_System_List_ID] = #2,
[Container_Size_List_ID] = #3,
[Active_Directory_List_ID] = #4
where ([Request_ID] = #5)
select [IaaS_ID],
[Provision_Status_Code],
[Provision_Status_Text],
[Provision_Phase],
[Last_Update_Time],
[Canceled]
from [dbo].[Queue_Server_Provision]
where ##ROWCOUNT > 0 and [Request_ID] = 5',
N'#0 nvarchar(16),
#1 uniqueidentifier,
#2 uniqueidentifier,
#3 uniqueidentifier,
#4 uniqueidentifier,
#5 uniqueidentifier',
#0=N'IaaSTest222',
#1='31097372-E4A6-461D-AFCC-BFAF069A6710',
#2='CF44FE08-56DE-4A7D-813A-08A7AD215E8B',
#3='15AEB74F-E0CB-4219-AC69-8C623DE8DF46',
#4='EA08BB7E-5C1F-4F6B-83D6-4BF9F6C55FF7',
#5='34CA5F9C-2BF8-40E5-8BDD-5DE7364C18C3'

This looks very much like Entity Framework "thinks" that the Provision_Status_Text column is generated in the database - either because it's an identity (unlikely for a string column) or because it's a computed column.
Indication for this is:
The column is not part of the set expression in the update statement although you changed that column. If the column is database generated this is expected.
The column is returned in the sql select expression. For a database generated column this is expected again because EF wants to update the entity on client side with the current computed database values after an insert or update.
The same applies by the way for the other columns that occur in the select statement.
If you are using Code-First workflow check if those properties are annotated with one of the
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
attributes or if
....HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)
....HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed)
is used with Fluent API.
If you are using Database-First or Model-First workflow with EDMX check your EDMX file for StoreGeneratedPattern="Identity" or StoreGeneratedPattern="Computed" attributes. You should find these settings in the designer surface as well.
It does not necessarily mean that the column is really generated in the database. But if one of these settings is in the model metadata EF will assume it is and behave the way you see it. It could mean that database and model are "out of sync" for some reason because some manual changes have been done in the database schema or the model perhaps without updating the other side.

Related

DbUpdateConcurrencyException on insert

I am inserting data into a table for an integration test using Entity Framework 6. When I execute the following code, I get a DbUpdateConcurrencyException on the call to SaveChanges().
using (var context = new CONTACTEntities())
{
context.Facilities.AddRange(facilities);
context.SaveChanges();
}
I'm not sure why this is happening. The table should be empty since the tables are dropped/created before the test runs and this is the only place in the test that I insert any data into this table. Any ideas?
If you are using SQLServer and you have a datetime column in your table, change the columns type to datetime2(7).
It sounds strange but it works. The explanation is something about milliseconds.
You must be aware of how Entity Framework handle keys in your table. In my code I set the HasDatabaseGeneratedOption. It can be otherwise in your code.
public class IceCatCategoryMap : EntityTypeConfiguration<IceCatCategory>
{
public IceCatCategoryMap()
{
ToTable("SemlerServices_IceCatCategory");
HasKey(m => m.Id);
Property(m => m.Id).IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
}
}

Unicode with Entity Framework

I have a table with nvarchar field (MS SQL Server 2008 R2). For testing, this code works fine:
Update [Screenshots] set name=N'Значение' where id=230246
right now I created Entity Framework model, I have set Unicode as True
then I try to update my record:
public void Put(FormDataCollection formData)
{
string filename = formData.Get("filename");
var screenshot = c.Screenshots.Where(p => p.filename == filename).FirstOrDefault();
if (screenshot != null)
{
screenshot.name = formData.Get("description");
c.SaveChanges();
}
}
but I got "?????" instead of unicode value. How to do it? I know about AsNonUnicode method, but this method works only for LINQ.
Are you sure that formData.Get("description") returns UTF-8 string (that it isn't converted somewhere)?
What is your approach in entity framework? Code-first/Design-first/Database-first?
Try to remove database and recreate - remove database and then in designer right click -> Generate database from model...
Get Entity Framework Profiler from Nu-get package manager and see what query is sending to database.

how does ADO.NET know that a SQL Server concurrency violation has occurred?

I don't understand how ADO.NET recognizes a concurrency violation unless it's doing something beyond what I'm telling it to do, inside its "black box".
My update query in SQL Server 2000 does something like the following example, which is simplified; if the rowversion passed to the stored proc by the client doesn't match the rowversion in the database, the where-clause will fail, and no rows will be updated:
create proc UpdateFoo
#rowversion timestamp OUTPUT,
#id int,
#foodescription varchar(255)
as UPDATE FOO set description = #foodescription
where id = #id and rowversion = #rowversion;
if ##ROWCOUNT = 1
select #rowversion from foo where id = #id;
I create a SqlCommand object and populate the parameters and assign the command object to the SqlDataAdapter's UpdateCommand property. Then I invoke the data adapter's Update method.
There should indeed be a concurrency error because I deliberately change the database row in order to force a new rowversion. But how does ADO.NET know this? Is it doing something more than executing the command?
In the RowUpdated event of the SqlDataAdapter there will be a Concurrency error:
MySqlDataAdapter += (sender, evt) =>
{
if ((evt.Status == UpdateStatus.Continue) && (evt.StatementType == StatementType.Update))
{
// update succeeded
}
else
{
// update failed, check evt.Errors
}
}
Is ADO.NET comparing the rowversions? Is it looking at ##rowcount?

Entity Framework 4: Selecting Single Record

I'm currently planning on switching my "manual query-writing" code to a nice SQL framework, so I can leave the queries or sql things to the framework, instead of writing the queries myself.
Now I'm wondering how I can get a single record from my table in Entity Framework 4?
I've primarily used SQL like SELECT * FROM {0} WHERE Id = {1}. That doesn't work in EF4, as far as I'm concerned.
Is there a way I can select a single ID-Based record from my Context?
Something like:
public Address GetAddress(int addressId)
{
var result = from Context.Addresses where Address.Id = addressId;
Address adr = result as Address;
return Address;
}
Thank you!
var address = Context.Addresses.First(a => a.Id == addressId);
You can use Single or First methods.
The difference between those methods is that Single expects a single row and throws an exception if it doesn't have a single row.
The usage is the same for both of them
(Based on VS 2015) If you create an .edmx (Add --> ADO.NET Entity Data Model).
Go through the steps to created the ".edmx" and use the following to run the stored procedure. emailAddress is the parameter you are passing to the stored procedure g_getLoginStatus. This will pull the first row into LoginStatus and status is a column in the database:
bool verasity = false;
DBNameEntities db = new DBNameEntities(); // Use name of your DBEntities
var LoginStatus = db.g_getLoginStatus(emailAddress).FirstOrDefault();
if ((LoginStatus != null) && (LoginStatus.status == 1))
{
verasity = true;
}

Execute StoredProcedure in CodeFirst 4.1

I understand stored procedures mapping is not supported by my understanding is that I should be able to call stored procedures.
I have quite a few complex stored procedures and with the designer I could create a complex type and I was all good.
Now in code first let's suppose I have the following stored procedure, just put together something silly to give an idea. I want to return a student with 1 address.
In code I have A Student and Address Entity. But no StudentAddressEntity as it's a link table.
I have tried the following but I get an error
Incorrect syntax near '."}
System.Data.Common.DbException {System.Data.SqlClient.SqlException}
ALTER Procedure [dbo].[GetStudentById]
#StudentID int
AS
SELECT *
FROM Student S
left join StudentAddress SA on S.Studentid = sa.studentid
left join Address A on SA.AddressID = A.AddressID
where S.StudentID = #StudentID
C# code:
using (var ctx = new SchoolContext())
{
var student = ctx.Database.SqlQuery<Student>("GetStudentById,#StudentID",
new SqlParameter("StudentID", id));
}
Any examples out there how to call sp and fill a complexType in code first, using out parameters etc.. Can I hook into ADO.NET?
Trying just an SP that returns all students with no parameters I get this error
System.SystemException = Cannot create a value for property
'StudentAddress' of type
'CodeFirstPrototype.Dal.Address'. Only
properties with primitive types are
supported.
Is it because I have in a way ignore the link table?
Any suggestions?
I believe that your exception actually is:
Incorrect syntax near ','.
because this is invalid statement: "GetStudentById,#StudentID". It should be without comma: "GetStudentById #StudentID".
The problem with stored procedures in EF is that they don't support loading navigation properties. EF will materialize only the main entity and navigation properties will not be loaded. This is solved for example by EFExtensions. EFExtensions are for ObjectContext API so you will have to check if it is also usable for DbContext API.
Using EFExtentions it will look something like
using (var context = new SchoolContext())
{
var command = context.CreateStoreCommand("GetStudentById", CommandType.StoredProcedure,
new SqlParameter("StudentID", id));
using (command.Connection.CreateConnectionScope())
using (var reader = command.ExecuteReader())
{
// use the reader to read the data
// my recommendation is to create a Materializer using EFExtensions see
// http://blogs.msdn.com/b/meek/archive/2008/03/26/ado-entity-framework-stored-procedure-customization.aspx
// ex
var student = Student.Materializer.Materialize(reader).SingleOrDefault();
return student;
}
}