I am trying to update an entity as follows-
[HttpPost]
public ActionResult EditRa(RetailersAssistant ra)
{
var existingRa = Db.RetailersAssistants.Find(ra.RaId);
existingRa = ra;
Db.SaveChanges();
return RedirectToAction("RaList", "Admin");
}
But it's not updating the database. No exception also. Any help?
You should set the mode of entity as "modified". Please find the solution below:
[HttpPost]
public ActionResult EditRa(RetailersAssistant ra)
{
var existingRa = Db.RetailersAssistants.Find(ra.RaId);
existingRa = ra; // If it doesn't work then you can copy each property of ra to existingRa one by one.
Db.Entry(existingRa).State = System.Data.Entity.EntityState.Modified;
Db.SaveChanges();
return RedirectToAction("RaList", "Admin");
}
You need to update each property of existingRa entity. Now, you just assigning new object
Related
A lot of code examples use either named parameters or execute stored procedures, but not both. How do I do so when I don't have a pre-defined entity type being selected by the stored proc? (Which means that .FromSqlRaw is out.)
The code below allows you to call a stored procedure and generate a list of named parameters, just from the list of SqlParameters.
var sqlParams = new SqlParameter[] {
new SqlParameter("p1", valOfP1),
new SqlParameter("p2", valOfP2),
new SqlParameter("pOut", SqlDbType.Int)
{
Direction = System.Data.ParameterDirection.Output
}
};
// OK to use the same names as for the SqlParameter identifiers. Does not interfere.
var sql = "myStoredProc " + String.Join(", ", sqlParams.Select(x =>
$"#{x.ParameterName} = #{x.ParameterName}" +
(x.Direction == ParameterDirection.Output ? " OUT" : "")
));
myDbContext.Database.ExecuteSqlRaw(sql, sqlParams);
var outputId = (int)(sqlParams.First(p => p.Direction == ParameterDirection.Output).Value);
Try Below example code which lets you call sp and store result in a
datatable.
using (var command = db.Database.GetDbConnection().CreateCommand())
{
command.CommandText = "sp_name";
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add(new SqlParameter("key", "Value"));
db.Database.OpenConnection();
using (var result = command.ExecuteReader())
{
var dataTable = new DataTable();
dataTable.Load(result);
return dataTable;
}
}
Here Product is class where you can define property whatever you want to retrieve from procedure
public class DataBaseContext : DbContext
{
public DataBaseContext() : base("name=DataBaseContext")
{
}
public DbSet<Product> Products { get; set; }
}
-- // This below code you need to write where you want to execute
var context = new DataBaseContext();
var products = context.Database.SqlQuery<Product>("EXEC GetProductsList #ProductId",
new SqlParameter("#ProductId", "1")
).ToList();
Add DbSet as below code
public DbSet ChartModels { get; set; }
Set Dbset AS a HasNoKey() if it is use only for Query
builder.Entity< ChartModel >().HasNoKey();
Call Sp as below Code
string sqlQuery = "EXECUTE dbo.GetDashboardChart";
SqlParameter p = new SqlParameter("#name", "test");
var lst = await ChartModels.FromSqlRaw(sqlQuery,p).ToListAsync();
Pretty much the same as SAEED said above. Add the code below to your DbContext class:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Berk>().HasNoKey();
}
[NotMapped]
public DbSet<Berk> Berks { get; set; }
public virtual List<Berk> CallSP(string berkberk) =>
Berks.FromSqlRaw("exec dbo.berk #berkBerk = {0}", berkberk).ToList();
called with:
List<Berk> berk = = _whateverYouCalledTheDbContext.CallSP("berk berk berk!");
Will return a DbSet where Berk is just an object that matches the return values from the stored procedure. There is no Berks table in the database, but you have your stored procedure return values to play with as you wish.
I thought I had this approach nailed down but I'm getting an odd result. I have a form that passes in a ViewModel to my controller. From there the controller extracts the passed in data, assigns it to the entity and then calls Update and SaveChanges. However, the update wipes all data from my database row leaving only the modified data I passed in.
It was my understanding that calling Update meant that ef could detect which items were modified and update accordingly. Have I got this wrong?
Here is my code
[HttpPost]
public IActionResult AddPositionFixture(ViewPosition model)
{
if (ModelState.IsValid && model != null)
{
var fixture = new Fixture
{
Id = model.FixtureId,
WorkRole = model.TempScope
};
_context.Fixture.Update(fixture);
_context.SaveChanges();
}
return View();
}
My context is injected beforehand:
private readonly MyContext _context;
public PositionController(HaglandContext context)
{
_context = context;
}
I'm trying to implement item versioning using EF, and what I need to know is whether or not the entity which I called Update() on actually got changed, so I can increment its version number. How can I obtain this information?
My repository Update function looks like this:
public virtual void Update(T entity)
{
dbset.Attach(entity);
dataContext.Entry(entity).State = EntityState.Modified;
}
What I opted for afterall was comparing the serialized versions of the 2:
public void UpdateProduct(Product product)
{
var productInDb = GetByID(product.Id);
if (!JToken.DeepEquals(JsonConvert.SerializeObject(product), JsonConvert.SerializeObject(productInDb)))
product.CurrentVersion++;
product = Update(product);
}
You can get the information from the entity state.
If a property has been changed, the state will be "Modified" otherwise "Unchanged".
using (var ctx = new TestContext())
{
var first = ctx.Entity_Basics.First();
var x1 = ctx.IsModified(first); // false
first.ColumnInt = 9999;
var x2 = ctx.IsModified(first); // true
}
public static class Extensions
{
public static bool IsModified <T>(this DbContext context, T entity) where T : class
{
return context.Entry(entity).State == EntityState.Modified;
}
}
This is the code that I have in my controller:
[HttpPost]
public ActionResult UpdateArticle(Article article)
{
if (ModelState.IsValid)
{
article.DateAdded =
this.articleRepository.GetSingle(article.ID).DateAdded;
article.DateModified = DateTime.Now;
this.articleRepository.Update(article);
return this.Redirect("~/Admin");
}
else
{
return this.Redirect("~/Admin/UnsuccessfulOperation");
}
}
From the view the data comes updated. I have a generic repository which handles the saving.
Update looks like this:
public virtual void Update(T entity)
{
//this.context.Entry(entity).State = EntityState.Modified;
this.context.SaveChanges();
}
If I uncomment the first line
An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple
objects with the same key.
exception is thrown. When commented nothing is saved.
Any help is appreciated.
UPDATE
Ok the problem seems to be that the updated article is not "part" of the context so when I pass it to the update nothing happens. If I get the entity from the repository itself and pass the new values and after that pass this entity everything works as expected. This piece of code actually updates the date in the repository:
var art = this.articleRepository.GetSingle(article.ID);
art.Text = article.Text;
this.articleRepository.Update(art);
What I don't get is that this works too:
var art = this.articleRepository.GetSingle(article.ID);
art.Text = article.Text;
this.articleRepository.Update(article);
UPDATE 2
Thanks to Vitaliy I now know that attaching is the key, but when I try to attach the new entity I get the same ugly exception
An object with the same key already...
UPDATE 3
As I am not allowed to answer my own question in less than 8h I suppose I have to make another update.
Ok, so this is what I did in order to successfully detach the old and attach the new entity:
public virtual void Update(T entity, object id)
{
this.context.Entry(this.GetSingle(id)).State = EntityState.Detached;
this.context.Entry(entity).State = EntityState.Added;
this.context.Entry(entity).State = EntityState.Modified;
this.context.SaveChanges();
}
I will think of a better way to pass the ID, as it is already part of the entity, perhaps with and interface "myInterface" that has the ID property in it and T will be of type "myInterface".
Thanks a lot to Vitaliy.
You are updating article, which is not attached to Context, thus nothing will be saved.
Probably you intention was to change DateModified then you should do it like this:
public ActionResult UpdateArticle(Guid articleID)
{
if (ModelState.IsValid)
{
var article =
this.articleRepository.GetSingle(articleID);
article.DateModified = DateTime.Now;
this.articleRepository.Update(article);
return this.Redirect("~/Admin");
}
else
{
return this.Redirect("~/Admin/UnsuccessfulOperation");
}
}
I'll try to keep this short and concise.
I got my controller here...
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(CustomObject myCustomObject)
{
...
}
Where myCustomObject looks great. But, if I want to save this using the entity framework, I need to do something like this...
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(CustomObject myCustomObject)
{
CustomObject existingObject = repository.GetCustomObject(myCustomObject.ID);
// Set all the attributes of myCustomObject to existingObject
existingObject.SomeMapperFunction(myCustomObject)
repository.Save();
}
Is there a way I can keep from doing this mapping excersise?
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int id)
{
CustomObject existingObject = repository.GetCustomObject(id);
TryUpdateModel(existingObject);
// You additionaly can check the ModelState.IsValid here
repository.Save();
}