I have landed up in a situation here.
I am loading the User from a custom function here :
public User GetUserById(int Id)
{
var User = DBContext.Users.SingleOrDefault(x=>x.Id == Id);
return User;
}
The problem is in the controller where I call this!
var User = GetUserById(Id);
User.Language = UserModel.Language;
//UpdateModel(User); //I tried this but not working.
DBContext.SaveChanges();
The database is not being updated.
I tried loading the User in the controller directly with linq and things go fine.
But, Why is it not working the other way?
Is there any workaround to make it work with this function?
Isn't there any function like DBContext.Users.Update(User). I remember using something similar, but am not able to recollect!
As EBrown said, they need to be the same instance of DbContext. I'm betting your service uses one context and the controller another. So now when it gets to the controller it is disconnected and not tracked by EF.
The solution is to reconnect it to the context used by the controller (there are other ways to achieve this as well).
var User = GetUserById(Id); // returns a disconnected user
User.Language = UserModel.Language;
// Attach back to context and tell EF it is updated
DBContext.Users.Attach(User);
DBContext.Entity(User).State=EntityState.Modified;
DBContext.SaveChanges();
If this is your postback code, you could just as well write aUserUpdate function:
public void UpdateUser(UserModel userViewModel)
{
var userEntity = DBContext.Users.Find(userViewModel.Id); // Get your user from database
Mapper.Map(userViewModel, userEntity); // Use Automapper to move the changed fields into your entity
DbContext.SaveChanges();
}
Then your controller POST is simply:
if (ModelState.IsValid)
{
UpdateUser(UserModel);
// redirect to list or where ever...
}
Related
I am working on an application that should take data from one server and put the data into my database. I am currently struggling to update the database on startups.
I tried several approaches like creating an action which is calling a model which updates the database (with no luck), I tried to research if there is a way to do it in Startup class, but again with no luck.
I have these methods for now
TfsMethods.cs (Models class)
public TfsMethods(ApplicationDbContext db)
{
_db = db;
}
public void UpdateDbBranches()
{
var branches = GetAllBranches();
var dbBranches = _db.Branches;
foreach (var branch in branches)
{
if (dbBranches.Where(x => x.BranchName == branch.BranchName) == null)
{
_db.Add(branch);
}
}
}
where _db is ApplicationDbContext and GetAllBranches() is a method which gets data from one server and I want to put these into my DB.
BranchController.cs (Controller class)
public IActionResult UpdateDbBranches()
{
TfsMethods tfs = new TfsMethods( _db );
try
{
tfs.UpdateDbBranches();
return Ok();
}
catch( Exception e )
{
return Problem( e.ToString() );
}
}
The issue here is that I don't know what to call it on startups, even on razor page or Startup.cs
Is this somehow possible or is there any implementation that could help me with this issue?
There are several useful answers already available at:
Application startup code in ASP.NET Core
However, you should first consider if you really want to do this on startup or on a schedule. See Quartz.net for example: https://www.infoworld.com/article/3529418/how-to-schedule-jobs-using-quartznet-in-aspnet-core.html
If you're trying to do so-called Database Seeding, these links (and links in those discussions) may be useful to you:
https://github.com/Homely/Homely.AspNetCore.Hosting.CoreApp/issues/11
https://github.com/dotnet/aspnetcore/issues/10137
https://github.com/App-vNext/Polly/issues/638
I have just read about TransactionScope. It is very good and informative.
First of all, I was wondering if I really need transactions in MVC 4 / EF 6+. The reason for that is we always invoke DbContext.SaveChanges() to save changes. I'm wondering if SaveChanges() is something that simulates transaction close meaning if I invoke SaveChanges() I commit a transactions.
On the other hand, if I need transactions, then how to implement TransactionScope in MVC / EF applications. My scenario is something similar to the steps below:
I save valid record in database
I save a copy of an old and a new record in another table which is sort of archived version of the original table
I save user's activity in another table
I also provided code. As you can see if something goes wrong in the middle I have inconsistent data. I would be grateful for some examples on how to use TransactionScope. I may also need more to save in other tables. I would like to be certain either I save everything or nothing, such that I save everything if transaction is OK or roll back anything that happened up to the problem.
Thanks.
[HttpPost]
public ActionResult Edit(ApplicationViewModel viewmodel)
{
using(MyDbCOntext dbContext = new MyDbContext())
{
if(!MoselState.IsValid)
return View(application);
// Copy old data from database and assign to an object
ApplicationArchive applicationOld = CopyApplicationFromDB(db, viewmodel.ApplicationID);
// Update model
if (TryUpdateModel(applicationNew), null, null, new string[] { "ApplicationID" })
{
try
{
dbContext.Entry(userToUpdate).State = EntityState.Modified;
dbContext.SaveChanges();
// Archive old application
ApplicationArchive applicationNew = CopyApplicationFromDB(db, viewmodel.ApplicationID);
try
{
dbContext.ApplicationsArchive.Add(applicationOld);
dbCOntext.ApplicationsArchive.Add(applicationNew);
dbContext.SaveChanges();
// Register user activity
string username = GetUserNameFromCookie();
UserActivity useractivity = new UserActivity() { UserName = username, activity = "edit", Table = "application" };
try
{
dbContext.UserActivities.Add(useractivity);
dbContext.SaveChanges();
return RedirectView("Index");
}
}
}
catch
{
ModelState.AddModelError("", "Cannot update this application");
}
}
//
return View(application);
}
}
You need to wrap your database operation within a DbContextTransaction. See this link for Entity Framework transaction examples:
https://msdn.microsoft.com/en-us/data/dn456843.aspx
Let's assume that the below method lives in a WCF service. The UI retrieved an instance of the Status object, and makes a subsequent call to the service using this method. Instead of assigning the status to the user as I would expect, it attempts to insert the status. What am I doing wrong?
void Method(Status status)
{
//not sure if this is even needed, the status never changed
context.Statuses.ApplyChanges(status);
//get the first user from the database
User user = context.Users.Where(u => u.Id = 1).First();
//set user status to some existing status
user.Status = status;
//this throws an exception due to EF trying to insert a new entry
//into the status table, rather than updating the user.StatusId column.
context.SaveChanges();
}
The problem is that you are working with attached user. When the STE is attached to the context it behaves exactly in the same way as any other entity. More over its self tracking mechanism is not activated. So you must attach the status to the context before you set it to the user or it will be tracked as a new entity which has to be inserted:
void Method(Status status)
{
User user = context.Users.Where(u => u.Id = 1).First();
context.Attach(status);
user.Status = status;
context.SaveChanges();
}
Try this instead:
using (Entities ctx = new Entities())
{
ctx.Statuses.Attach(status);
ObjectStateEntry entry = ctx.ObjectStateManager.GetObjectStateEntry(status);
entry.ChangeState(EntityState.Modified);
//get the first user from the database
User user = ctx.Users.Where(u => u.Id = 1);
//set user status to some existing status
user.StatusID = status.StatusID;
ctx.SaveChanges();
}
Here's a tutorial on CRUD with Entity Framework if you're interested.
Have to write an answer because I can't yet comment on another answer (rep score < 50) [something weirdly not right about that, but I get why it's like that] because I wanted to add some clarity to #Ladislav's answer.
The Status object coming in from the WCF call did not come from the same context you are using to find the User object, so the tracking code is not fixed up with that context. This is why attaching it will allow you to save the assignment without the context thinking that status is a new entity requiring an insert into the database.
Using ASP.NET MVC and Entity Framework, I encounter some attach/detach errors when I need it to write changes to the database.
First here's how I get the records from my repository:
public PublishedApplication GetPublishedApplication(int id)
{
return dal.ExecuteFirstOrDefault(
context.PublishedApplication.Include("Customers")
.Where(w => w.Id == id));
}
Note that this is not being detached, and it has MergeOption = AppendOnly.
Another place, I call a method in my repo to attach a customer to the application:
public void AttachCustomer(int applicationId, int customerId)
{
var app = new PublishedApplication{ Id = applicationId};
var customer = new Customer { Id = customerId};
try
{
context.AttachTo("PublishedApplication", app);
context.AttachTo("Customer ", customer );
app.Customers.Add(customer);
context.SaveChanges();
}
catch
{
throw;
}
}
This, of course, gives me an error that the objects (app and customer) are already attached to an object context.
So I need to detach my objects in my repository. This is also more correct as I don't need to throw "query related information" around the web. But how can I do this? If I detach the entity in my GetPublishedApplication method, my graph of related data is lost, and I can't afford that. I need that graph elsewhere on my site. Can't use merge option NoTracking either.
So what options do I have?
Thanks in advance!
I think, there isn't easy solution for reattaching entities.
May be this post will help you:
Reattaching Entity Graphs with the Entity Framework on codeproject.com
1) I add a new entity to the context and call _context.SaveChanges(). Entity is added as expected
2) I update the same entity and call _context.SaveChanges() I put a break point immediately after and inspect the _context and my update is reflected on the entity AND is indeed saved to the DB.
3) I call _context.Set< T >().ToList() later in my code base and the update is NOT reflected on the entity. (_context does not reflect the updated value at this point)
What could possibly be the cause and what can I do to resolve? Any help would be greatly appreciated
Responding to request for code..
From the repository...
public List<T> GetAll()
{
return _context.Set<T>().ToList();
}
public void SaveChanges()
{
_context.SaveChanges();
var xxx = _context.Customers.ToList();
}
From the call to get all...
var customersToUpdate = _customerManager.GetAllCustomers();
From the CustomerManager...
public List<Customer> GetAllCustomers()
{
return _customerRepository.GetAll();
}
Pretty basic stuff.
Are you sure that you use only one instance of the _customerRepository? And that every time you update the _context you do it in the same context under _customerRepository ? It sounds like you have multiple instance, one get updated while the others dont
Basically you need to tell EF that you updated something.
Easiest way of doing that is:
var customer = _context.Customers.First();
customer.Name = "new name";
_context.Entry(customer).State = EntityState.Modified;
_context.SaveChanges();
Or you can be more specific of what is changed like below:
customer.Name = "new name";
context.Entry(customer).Property(u => u.Name).IsModified = true;
_context.SaveChanges();
You can enable automatic changes detection like that:
context.Configuration.AutoDetectChangesEnabled = true;
In this case
DbSet.Find
DbSet.Local
DbSet.Remove
DbSet.Add
DbSet.Attach
DbContext.SaveChanges
DbContext.GetValidationErrors
DbContext.Entry
DbChangeTracker.Entries
all will automatically detect changes.