SaveChanges not setting value, selecting existing value instead - asp.net-mvc

When trying to commit a modified entry to the database, Entity Framework is selecting values for two properties as opposed to setting them.
The code to commit the entity to the database is as follows:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(Till till)
{
if (ModelState.IsValid)
{
string username = User.Identity.Name.Substring(User.Identity.Name.LastIndexOf('\\') + 1);
till.ModifiedDate = DateTime.Now;
till.ModifiedByUid_FK = db.Users.Where(m => m.Name.ToLower() == username.ToLower()).First().UserUid_PK;
db.Entry(till).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index/" + (int)Session["siteid"]);
}
ViewBag.SiteUid_FK = new SelectList(db.Sites, "SiteUid_PK", "Name", till.SiteUid_FK);
ViewBag.ModifiedByUid_FK = new SelectList(db.Users, "UserUid_PK", "EHLogin", till.ModifiedByUid_FK);
ViewBag.CreatedByUid_FK = new SelectList(db.Users, "UserUid_PK", "EHLogin", till.CreatedByUid_FK);
return View(till);
}
When viewed in the profiler, it looks like this:
exec sp_executesql N'update [dbo].[Till]
set [NetworkId] = #0, [MID] = #1, [SiteUid_FK] = #2, [Location] = null, [MasterTillNo] = #3,
[IsMaster] = #4, [IsBackOffice] = #5, [IsCurrent] = #6, [ModifiedByUid_FK] = #7,
[CreatedByUid_FK] = #8, [ProcessFiles] = #9
where ([TillUid_PK] = #10)
select [ModifiedDate], [CreatedDate]
from [dbo].[Till]
where ##ROWCOUNT > 0 and [TillUid_PK] = #10',N'#0 varchar(50),#1 int,#2 int,#3 int,#4 bit,#5 bit,#6
bit,#7 int,#8 int,#9 bit,#10 int',
#0='',#1='',#2=4,#3=42,#4=1,#5=0,#6=1,#7=4,#8=1,#9=1,#10=699
I'm guessing there's some property of the field in the database that EF uses to determine this functionality but I can't figure out what it is. If anyone has any information that'd be fantastic :)
Edit 1
Using Ibrahim's answer below, results in relatively similar SQL:
exec sp_executesql N'declare #p int
update [dbo].[Till]
set #p = 0
where ([TillUid_PK] = #0)
select [ModifiedDate], [CreatedDate]
from [dbo].[Till]
where ##ROWCOUNT > 0 and [TillUid_PK] = #0',N'#0 int',#0=687

This typically happens when properties have the data annotation
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
or the fluent mapping
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed)
or the StoreGeneratedPattern is Computed in the edmx file.
I'd guess that there is a trigger or a default value on ModifiedDate and CreatedDate on the columns in the database. Maybe it's even useless to set them in your application code.

I have had bad luck with the following also:
db.Entry(entity).State = EntityState.Modified;
So I suggest trying to do the following:
//Get the existing Till
var existingTill = db.Tills.Find(till.TillId);
//Save changes for only changed properties
db.Entry(existingTill).CurrentValues.SetValues(till);
db.SaveChanges();

Related

Database.ExecuteSqlCommand returns incorrect rowcount

I'm using context.Database.ExecuteSql to update a table. The update with where clause is executed correctly and the record is updated. However the method returns 2 for rowcount instead of 1. When I execute the update statement in SSMS, the result rowcount returned is 1. Can someone provide insight on this?
string query =
string.Format("update {0} set Description = '{1}', Code = '{2}', LastUpdatedBy = '{3}', LastUpdatedDate = '{4}' where ID = {5};",
tableName,
description,
code,
lastUpdatedBy,
lastUpdatedDate,
ID);
int rowCount = 0;
string message = string.Empty;
using (DBContext context = new DBContext())
{
rowCount = context.Database.ExecuteSqlCommand(TransactionalBehavior.EnsureTransaction, query);
}
return rowCount == 0 ? //this return 2 instead of 1.
new SaveResult(SaveResult.MessageType.Error, string.Format("There was an error updating a record in the {0} table.", tableName), "Index") :
new SaveResult(SaveResult.MessageType.Success, string.Format("The update of {0} was successful.", tableName), "Index");
This returns rowcount = 1 in SSMS:
update zAddressTypes
set Description = 'Current', Code = '101122', LastUpdatedBy = 'user', LastUpdatedDate = '10/20/2014 12:17:26 PM'
where ID = 1;
DECLARE #RowCount INTEGER = ##ROWCOUNT;
select #RowCount;
The rowcount is being returned separately. What you are seeing here is the exit status of the query.
ExecuteSqlCommand return value is for the status of query not for row count. You may want to look into using a datareader or something similar to return the rowcount.
It is the way the datacontext works, see this link:
Entity Framework: Database.ExecuteSqlCommand Method
Apparently the command is updating two records.
Do you have a trigger on your table? I confirmed this behavior can be caused by a trigger as the rows affected by the trigger are added to the row count affected by your SQL command. I commonly check for a 0 or >0 return value to know if anything was affected. You could also return an output variable if you're calling a stored procedure.

MVC Enity Framework get KEY attribute from table

I am trying to extract the [key] value from a table.
This is for a logging method which looks like this:
private List<Log> GetAuditRecordsForChange(DbEntityEntry dbEntry, string userId)
{
List<Log> result = new List<Log>();
DateTime changeTime = DateTime.Now;
// Get the Table() attribute, if one exists
TableAttribute tableAttr = dbEntry.Entity.GetType().GetCustomAttributes(typeof(TableAttribute), false).SingleOrDefault() as TableAttribute;
// Get table name (if it has a Table attribute, use that, otherwise get the pluralized name)
string tableName = tableAttr != null ? tableAttr.Name : dbEntry.Entity.GetType().Name;
// Get primary key value
string keyName = dbEntry.Entity.GetType().GetProperties().Single(p => p.GetCustomAttributes(typeof(KeyAttribute), false).Count() > 0).Name;
if (dbEntry.State == EntityState.Added)
{
result.Add(new Log()
{
LogID = Guid.NewGuid(),
EventType = "A", // Added
TableName = tableName,
RecordID = dbEntry.CurrentValues.GetValue<object>(keyName).ToString(),
ColumnName = "*ALL",
NewValue = (dbEntry.CurrentValues.ToObject() is IDescribableEntity) ? (dbEntry.CurrentValues.ToObject() as IDescribableEntity).Describe() : dbEntry.CurrentValues.ToObject().ToString(),
Created_by = userId,
Created_date = changeTime
}
);
}
The problem is to get the RecordID when a Record is added, when it get deleted or modified it works. (The code to get it is the same)
When I debug I also see that it has the KeyAttribute in the CustomAttributes base but not sure why it always shows up as 0.
I can debug more if needed
After savechanges you can fetch the newly created key. (Guess the key is generated automatically inserting a new record).
for me you have several solutions.
first solution:
enlist added entity from the context
SaveChanges
enumerate the enlisted entities to add log
SaveChanges
the problem (or not) here is that the business and the logging are not in the same transaction.
antother problem, depending on the implementation, is to prevent loging of log of log of log... This can be donne by filtering entities by typeName for example.
other solution:
add and ICollection<Log> to your entities.
the problem here is to unify the logs:
inheritance of entity, or
several log tables + a view
...
other solution
use trigger at database level
other solution
..., use cdc if you have Sql Server Enterprise Edition

How can I check results for select statement in MVC?

Hi this is the SP I have :
USE [Tracker_Entities]
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[uspHub]
#id int
AS
BEGIN
SELECT DISTINCT table1.UID, table1.url, Scope.ID
FROM table1 INNER JOIN
Scope ON table1.UID = Scope.newBrand
WHERE (table1.value = 0) AND (Scope.ID = #id)
ORDER BY table1.url
END
GO
When i run this SP in sql server by passing ID as parameter i am getting expected result. Now I need to check this SP in mvc. This is the way I am calling this SP in my MVC :
using (var ctx = new database_Entities())
{
int ID = 122;
ctx.uspHub(ID);
ctx.SaveChanges();
}
But when I put breakpoint in using statement and check for results, it is not displaying any results. I am struggling here for long time and i am not getting proper solution for this. So what are the steps in MVC to check results for SP which has select statements??
Update :
I got solution for this after using tolist. Now i am getting three results in list and i need to grab one result that is URL and pass it as input parameter.
My code :
int ID = 413;
var x = ctx.uspdHub(ID).ToList();
Here x has 3 results. I need to take one result from it.I tried doing x. but it doesn't show results after i type dot. How can i achieve this??
You have to Get the result into proper model/object.
List<YourEntity> model;
using (var ctx = new database_Entities())
{
int ID = 122;
model = ctx.uspHub(ID).toList();
//ctx.SaveChanges(); - no need to call SaveChanges
// - as you are not updating anything
}
Go through this article if you need more info. Call Stored Procedure From Entity Framework (The code above will work anyways...)
use...
using (var ctx = new database_Entities())
{
int ID = 122;
var result = ctx.uspHub(ID);
}
and add a break after the result to see whats in the result variable. Obviously, the sope of result will need to be moved, but I'm only showing here how you can see the data returned.
Try to use something like this:
using (var dataContext= new database_Entities())
{
int ID = 122;
SomeEntity[] result = dataContext.Database.SqlQuery<SomeEntity>("[dbo].[uspHub] #id",new SqlParameter("#id", ID)).ToArray();
}
It is good for me. I have used ORM EntityFramework to connect with DB.

linq to entities - updating tables with new values not working

The code below is updating the correct values into the OBJECT_TYPES table, but the OBJECT_ITEMS table is being overwritten but I am not sure why. Can anyone help?
var templateId = Request["id"].AsInt();
var dbcontext = new STDEntities1();
var query = dbcontext.OBJECT_TYPES.Where(o => o.ID == templateId);
var template = query.FirstOrDefault();
var newItem = new OBJECT_TYPES
{
CATEGORY_ID = template.CATEGORY_ID,
COMPANY_ID = template.COMPANY_ID,
OBJECT_NAME = "** Select A Name **",
HEIGHT = template.HEIGHT,
WIDTH = template.WIDTH,
TEMPLATE = template.ID
};
foreach (var field in template.OBJECT_ITEMS)
{
newItem.OBJECT_ITEMS.Add(field);
}
dbcontext.OBJECT_TYPES.Add(newItem);
dbcontext.SaveChanges();
this is happening because you are adding field which actually is an object that is being tracked by the dataContext/dbContext and even has an id. So the values are being overwritten.
Try creating the a new field OR try detaching the field from the context and then put the Id/Primary key to 0 and try inserting it again.

Insert into multiple database tables using Linq, ASP.NET MVC

I have a rather simple scenario where I have two tables in which I want to add data. They are managed with primary key/foreign key. I want to add new data into TABLE A and then retrieve the Id and insert into TABLE B.
I can certainly do it with a stored procedure, but I'm looking at trying to do it using Linq.
What is the best approach ?
I can certainly get the ID and do two separate inserts but that doesn't certainly seem to be a very good way of doing things.
db.Table.InsertOnSubmit(dbObject);
db.SubmitChanges();
Int32 id = dbOject.Id;
//Rest of the code
Any way to elegantly do this?
Do you have the relationship defined between the 2 tables in the object relational designed? If so, you can have linq take care of assigning the ID property of the second table automatically.
Example...
Table A – Order
OrderId
OrderDate
Table B – Order Item
OrderItemId
OrderId
ItemId
Code (Using LINQ-to-SQL):
Order order = new Order();
Order.OrderDate = DateTime.Now();
dataContext.InsertOnSubmit(order);
OrderItem item1 = new OrderItem();
Item1.ItemId = 123;
//Note: We set the Order property, which is an Order object
// We do not set the OrderId property
// LINQ will know to use the Id that is assigned from the order above
Item1.Order = order;
dataContext.InsertOnSubmit(item1);
dataContext.SubmitChanges();
hi i insert data into three table using this code
Product_Table AddProducttbl = new Product_Table();
Product_Company Companytbl = new Product_Company();
Product_Category Categorytbl = new Product_Category();
// genrate product id's
long Productid = (from p in Accountdc.Product_Tables
select p.Product_ID ).FirstOrDefault();
if (Productid == 0)
Productid++;
else
Productid = (from lng in Accountdc.Product_Tables
select lng.Product_ID ).Max() + 1;
try
{
AddProducttbl.Product_ID = Productid;
AddProducttbl.Product_Name = Request.Form["ProductName"];
AddProducttbl.Reorder_Label = Request.Form["ReorderLevel"];
AddProducttbl.Unit = Convert.ToDecimal(Request.Form["Unit"]);
AddProducttbl.Selling_Price = Convert.ToDecimal(Request.Form["Selling_Price"]);
AddProducttbl.MRP = Convert.ToDecimal(Request.Form["MRP"]);
// Accountdc.Product_Tables.InsertOnSubmit(AddProducttbl );
// genrate category id's
long Companyid = (from c in Accountdc.Product_Companies
select c.Product_Company_ID).FirstOrDefault();
if (Companyid == 0)
Companyid++;
else
Companyid = (from Ct in Accountdc.Product_Companies
select Ct.Product_Company_ID).Max() + 1;
Companytbl.Product_Company_ID = Companyid;
Companytbl.Product_Company_Name = Request.Form["Company"];
AddProducttbl.Product_Company = Companytbl;
//Genrate Category id's
long Categoryid = (from ct in Accountdc.Product_Categories
select ct.Product_Category_ID).FirstOrDefault();
if (Categoryid == 0)
Categoryid++;
else
Categoryid = (from Ct in Accountdc.Product_Categories
select Ct.Product_Category_ID).Max() + 1;
Categorytbl.Product_Category_ID = Categoryid;
Categorytbl.Product_Category_Name = Request.Form["Category"];
AddProducttbl.Product_Category = Categorytbl;
Accountdc.Product_Tables.InsertOnSubmit(AddProducttbl);
Accountdc.SubmitChanges();
}
catch
{
ViewData["submit Error"] = "No Product Submit";
}

Resources