I am updating existing data in a database. Basically, I am retrieving all data from the table and one by one I am updating each column manually. Do you think it's a good way? Or please suggest me another short way to do the same. My method is looking so long I mean a lot of lines to update.
[HttpPost]
public ActionResult SaveMovie(HttpPostedFileBase file, MovieViewModel model)
{
if (!ModelState.IsValid)
{
var viewModel = new MovieViewModel
{
ProHouses = _context.ProHouses.ToList()
};
return View("AddMovie", viewModel);
}
if (model.Movies.Id == 0)
{
if (file != null)
{
Guid RandomName = Guid.NewGuid();
var fileExtention = Path.GetExtension(file.FileName);
var FileName = RandomName + fileExtention;
var path = Path.Combine(Server.MapPath("~/MovieTitle"), RandomName + fileExtention);
file.SaveAs(path);
model.Movies.TitleURL = FileName;
}
_context.Movies.Add(model.Movies);
}
else
{
var movieInTable = _context.Movies.SingleOrDefault(m => m.Id == model.Movies.Id);
movieInTable.Budget = model.Movies.Budget;
movieInTable.Writer = model.Movies.Writer;
movieInTable.Country = model.Movies.Country;
movieInTable.Genre = model.Movies.Genre;
movieInTable.Duration = model.Movies.Duration;
movieInTable.Plot = model.Movies.Plot;
movieInTable.Name = model.Movies.Name;
movieInTable.ProHouseId = model.Movies.ProHouseId;
movieInTable.Rating = model.Movies.Rating;
movieInTable.Director = model.Movies.Director;
movieInTable.Year = model.Movies.Year;
movieInTable.TitleURL = model.Movies.TitleURL;
}
_context.SaveChanges();
ViewBag.Message = "Movie Added";
return View("Confirmation");
}
I am confused about this part:
else
{
var movieInTable = _context.Movies.SingleOrDefault(m => m.Id == model.Movies.Id);
movieInTable.Budget = model.Movies.Budget;
movieInTable.Writer = model.Movies.Writer;
movieInTable.Country = model.Movies.Country;
movieInTable.Genre = model.Movies.Genre;
movieInTable.Duration = model.Movies.Duration;
movieInTable.Plot = model.Movies.Plot;
movieInTable.Name = model.Movies.Name;
movieInTable.ProHouseId = model.Movies.ProHouseId;
movieInTable.Rating = model.Movies.Rating;
movieInTable.Director = model.Movies.Director;
movieInTable.Year = model.Movies.Year;
movieInTable.TitleURL = model.Movies.TitleURL;
}
Firstly, the written code is hard to reuse and you will have difficulties during the maintenance. Suppose a situation that you are repeating such code and use it in several files, suddenly you discover that another field is required and needs to be added. So you have to alter all the codes.
Second, it is recommended to not put your Data Manipulation codes in controller. Try to create another layer (class project) in order to put such codes. Using Automapper class library with absolutely help you reducing mappings.
Otherwise, as Travis suggested above, you can use a constructor in order to fill the properties.
Related
Hi I am working on an EF Using Model First.
I want to add more details in table that specify for special categorys
but when I add these details that depend on adding data in a product table I get an exception.
public static void addproduct(ProductViewModel vm ,string userid)
{
var model = Mapper.Map<ProductViewModel, Product>(vm);
model.CountSell = 0;
byte[] binaries = new byte[vm.postprofilimgae.ContentLength];
vm.postprofilimgae.InputStream.Read(binaries, 0, vm.postprofilimgae.ContentLength);
model.ProfileImage = binaries;
foreach (var file in vm.postProductimages)
{
var filedetails = new ProductImage();
var data = new byte[file.ContentLength];
filedetails.ContentLength = file.ContentLength;
filedetails.FileName = file.FileName;
file.InputStream.Read(data, 0, file.ContentLength);
filedetails.ProductImage1 = data;
filedetails.ProductID= model.ProductID;
model.ProductImages.Add(filedetails);
}
using (var db = new Entities())
{
model.ActivationID = db.ActivationStatus.Single(x => x.Name == "Active").ActivationID;
model.SubCategoryID = vm.SubCategoryID;
model.EmployeeID= db.Employees.Single(x => x.UserID == userid).EmployeeID;
model.CountSell = 0;
VichDetails detailsmodel = new VichDetails();
if (db.SubCategories.Single(x=>x.SubCategoryID == vm.SubCategoryID).MainCategoryID == db.MainCategories.Single(x=> x.Name == Categories.vehicles).MainCategoryID)
{
VichDetails moredetails = new VichDetails();
detailsmodel = Mapper.Map<ProductViewModel, VichDetails>(vm);
//detailsmodel.ProductID = model.ProductID;
db.VichDetails.Add(detailsmodel);
}
db.SaveChanges();
model.VichDetailsID = detailsmodel.Id;
db.Products.Add(model);
db.SaveChanges();
}
}
I get this exception:
In your Product you will want to consider adding:
public virtual VichDetail VichDetail { get; set; }
and then instead of:
if (db.SubCategories.Single(x=>x.SubCategoryID == vm.SubCategoryID).MainCategoryID == db.MainCategories.Single(x=> x.Name == Categories.vehicles).MainCategoryID)
{
VichDetails moredetails = new VichDetails();
detailsmodel = Mapper.Map<ProductViewModel, VichDetails>(vm);
db.VichDetails.Add(detailsmodel);
}
db.SaveChanges();
model.VichDetailsID = detailsmodel.Id;
db.Products.Add(model);
db.SaveChanges();
it would look like:
if (db.SubCategories.Single(x=>x.SubCategoryID == vm.SubCategoryID).MainCategoryID == db.MainCategories.Single(x=> x.Name == Categories.vehicles).MainCategoryID)
{
VichDetails detailsmodel = Mapper.Map<ProductViewModel, VichDetails>(vm);
model.VichDetails = detailsModel;
}
db.Products.Add(model);
db.SaveChanges();
The issue you are encountering is that while you are setting the new VichDetail ID on your Product before saving the product, you have only associated the Product, not necessarily the VichDetail. I.e.
if (db.SubCategories.Single(x=>x.SubCategoryID == vm.SubCategoryID).MainCategoryID == db.MainCategories.Single(x=> x.Name == Categories.vehicles).MainCategoryID)
If this condition is false, the VichDetail is not added to the DbContext.
The code is rather confusing to look at as you are creating a VichDetail, but then checking that condition before creating another VichDetail "moredetails" which doesn't look to be used, before mapping the original details from the view model. If that condition doesn't pass you will have an empty VichDetails (detailsmodel) with likely a default ID (0?) which would be set on your Product. (model)
You cannot simply move the model.VichDetailsID = detailsmodel.id inside your conditions, since you're relying on setting FK IDs which won't be available until the related entity is saved to the DbContext. Navigation properties are generally a lot easier to interact with than messing around with PKs and FKs in your entities. Let EF do the lifting for associating the relationships.
If your entities already have these navigation properties, then you'll want to use those and avoid setting FKs directly.
Please Help
This is how i'm updating....
[HttpPost, ActionName("Edit")]
public ActionResult Edit(Students model)
{
if (ModelState.IsValid)
{
using (DbAccess db = new DbAccess())
{
var ID=db.students.Find(model.id);
db.Entry(ID).State = EntityState.Modified;
//ID.name = model.name;
//ID.address = model.address;
//ID.age = model.age;
//ID.email = model.email;
//ID.isActive = model.isActive;
db.SaveChanges();
}
}
return View(model);
}
In the above code when i update separately than it works well but when i use db.Entry(...)...... than it doesn't work for me and it also not shows any error
You can try...
[HttpPost, ActionName("Edit")]
public ActionResult Edit(Students model)
{
if (ModelState.IsValid)
{
using (DbAccess db = new DbAccess())
{
var ID = db.students.Find(model.id);
//db.Entry(ID).State = EntityState.Modified;
ID.name = model.name;
ID.address = model.address;
ID.age = model.age;
ID.email = model.email;
ID.isActive = model.isActive;
db.SaveChanges();
}
}
return View(model);
}
When you are doing var ID=db.students.Find(model.id);
You don't need to use
db.Entry(ID).State = EntityState.Modified;
Because when you do Find you have real object of your dbContext, when you make changes on it(except on it primary key of course), your SaveChanges will detect it and update it accordingly.
You need to set State only when you are doing something like this
Students students = new Students(); //a new object which is not created using `Find`
students.name = "Heartlion";
students.address = "address text";
db.Entry(students).State = EntityState.Modified;
db.SaveChanges();
just replace this:
db.Entry(ID).State = EntityState.Modified;
//ID.name = model.name;
//ID.address = model.address;
//ID.age = model.age;
//ID.email = model.email;
//ID.isActive = model.isActive;
with:
UpdateModel(ID);
and you'll be fine;
In order for your method to work, you need to do like this:
db.Students .Attach(ID);
var entry = db.Entry(ID);
entry.State = EntityState.Modified;
entry.Property(x => x.name).IsModified = true;
entry.Property(x => x.address).IsModified = true;
....
db.SaveChanges();
Basically you need to attach the updated model then to tell to the context, which props are modified.
I have in my repository, another method which I use in some situations, when the update is not done in the controller, the method is:
public void Update(TEntity newEntity)
{
var oldEntity = Context.Set<TEntity>().Find(newEntity.Id);
Context.Entry(oldEntity).CurrentValues.SetValues(newEntity);
}
In this method, the newEntity is comming from the view, and the oldEntity is from the context.
UpdateModel can be used only in controllers, when I call the update outside of the controller, I use the above method. I prefer this methods because I do not need to explicitly tell which props are been modified. When you have a form with 10 props, and user is updating only 3 or 4, you need a lot of logic to determine which were modified.
PS - my entities are all implementing IEntityId, which is an interface with common properties, like Id, UpdateDate, InsertDate ..., this is why I can call newEntity.Id
I'm trying to create a partial view with a dynamic model but I get the following exception after converting the model to List
Partial View:
#model dynamic
#{
dynamic model;
var obj1ListType = new List<Obj1>().GetType();
var obj2ListType = new List<Obj2>().GetType();
Type unknown = Model.GetType();
if (unknown == obj1ListType)
{
model = new List<Obj1>(Model);
}
else if (unknown == obj2ListType)
{
model = new List<Obj2>(Model);
}
else
{
model = new List<Obj3>(Model);
}
}
The problem is when I try to use
var Obj = Model.FirstOrDefault();
I get the following exception:
'System.Collections.Generic.List' does not contain a definition for 'FirstOrDefault'
Any Ideas? Maybe another way to create a dynamic partial view?
Thanks
I am not sure what you are trying to do here but I modified your code a bit and it works. I had to change few things. Most important change is converting the Model (actually you should have written model that you created right there) to a list and then call FirstOrDefault() on it.
Working Code with some adjustment:
#model dynamic
#{
dynamic model;
var obj1ListType = new List<object>().GetType();
var obj2ListType = new List<object>().GetType();
Type unknown = Model.GetType();
if (unknown == obj1ListType)
{
model = new List<object>(Model);
}
else if (unknown == obj2ListType)
{
model = new List<object>(Model);
}
else
{
model = new List<object>(Model);
}
var data = model as List<object>;
var dataItem = data.FirstOrDefault();
<span>#dataItem</span>
}
Controller:
public ActionResult Partial1()
{
return View(new List<string>(){"Test1", "Test2"});
}
Prints:
Test1
I'm new to Entity Framework. I'm trying to update a record and save changes to the database.
public void SaveEdit(Gate gate)
{
try
{
using (dc = new GateEntities())
{
var query = (from tbsite in dc.tblSites
where tbsite.ID == gate.ID
select tbsite).FirstOrDefault();
query.CalledInAt = gate.CalledInAt;
query.CallerRequest = gate.CallerRequest;
query.ContactPersonOnSite = gate.ContactPersonOnSite;
query.Email = gate.Email;
query.EmailSitePerson = gate.EmailSitePerson;
dc.SaveChanges();
}
}
catch (Exception ex)
{
throw ex;
}
}
It gets no exceptions or error messages but it does not save the changes to the database. why it's not updating the record?
After You modify query object You should change it's state to Modified before calling context.SaveChanges(). Your context object should know about the entity that You modify. Assuming dc is Your context object:
query.CalledInAt = gate.CalledInAt;
//change other properties ..
dc.Entry(query).State = EntityState.Modified;
dc.SaveChanges();
That should work for You.
You have to use the entityframework to select your object, with that the result object will be track-able, so try this
using (var dc = new GateEntities())
{
var gate = dc.tblSites.Where(g => g.ID == date.ID).FirstOrDefault();
gate.CalledInAt = gate.CalledInAt;
gate.CallerRequest = gate.CallerRequest;
gate.ContactPersonOnSite = gate.ContactPersonOnSite;
gate.Email = gate.Email;
gate.EmailSitePerson = gate.EmailSitePerson;
dc.SaveChanges();
}
Also noticed this happening when the Entity doesn't have configured a primary Key.
On EF Core check your OnModelCreating and make sure entity.HasKey(e => e.TheKey); is present.
By the documentation you are not required to work with states: https://learn.microsoft.com/en-us/ef/core/get-started/?tabs=netcore-cli
var yourEntity = await context.FirstOrDefaultAsync(e => e.Id = 1);//You can also call FindAsync(id)
yourEntity.Name = "NewName";//This line will let EF Core knows the entity has been modify
await context.SaveChangesAsync();
Although you can check how to work with states so here: https://learn.microsoft.com/en-us/ef/ef6/saving/change-tracking/entity-state
And the code will look like:
var yourEntity = await context.FirstOrDefaultAsync(e => e.Id = 1);
yourEntity.Name = "NewName";
context.Entry(yourEntity).State = EntityState.Modified;
await context.SaveChangesAsync();
They are both the same, I honestly prefer manually setting the state (in big projects) sometimes EF Core loses tracking of some entities (this is a personal experience) so I double check updating the status as Added Or Modified.
Thanks
I am looking for a more better way to update a record using Entity Framework.
Below is what I am using now, where playerFromModel is data fetched from View.
public bool UpdatePlayer(PlayerEntity playerFromModel)
{
bool updateSuccessfull = false;
using (var context = new PlayerEntities())
{
var player = context.Player.Where(m => m.emailAddress == playerFromModel.EmailAddress).FirstOrDefault();
if (player != null)
{
player.emailAddress = playerFromModel.EmailAddress;
player.first_name = playerFromModel.FirstName;
player.last_name = playerFromModel.LastName;
player.alt_email_id1 = playerFromModel.AlternateEmailAddress;
player.street = playerFromModel.Street;
player.city = playerFromModel.City;
player.state = playerFromModel.State;
player.zip = playerFromModel.Zip;
player.country_code = playerFromModel.CountryCode;
player.phone1 = playerFromModel.Phone;
try
{
context.SaveChanges();
updateSuccessfull = true;
}
catch
{
updateSuccessfull = false;
}
}
}
return updateSuccessfull;
}
As you can see I have to manually map each of the fields and the same approach I have followed everywhere.
I was thinking that there definitely has to be a better way to do this.
Please guide me on this. Thanks.
You can just use TryUpdateModel. e.g.
bool updateSuccessfull = false;
using (var context = new PlayerEntities())
{
var player = context.Player.Where(m => m.emailAddress == playerFromModel.EmailAddress).FirstOrDefault();
if (player != null)
{
//Beware this will try to map anything it can. This can be dangerous
if(TryUpdateModel(player)){
try
{
context.SaveChanges();
updateSuccessfull = true;
}
catch
{
updateSuccessfull = false;
}
}
}
}
return updateSuccessfull;
}
I wouldn't though see here Real example of TryUpdateModel, ASP .NET MVC 3.
You could use Automapper or something similar as MiBu said. Create a ViewModel link is here of the Player and then map from that to the entity
//Get a PlayerUpdate ViewModel
using (var context = new PlayerEntities())
{
// fetch the domain model that we want to update - BTW I'd use a repository pattern but that is another debate
var player = context.Player.Where(m => m.emailAddress == playerFromModel.EmailAddress).FirstOrDefault();
if (player != null)
{
// Use AutoMapper to update only the properties of this domain model
// that are also part of the view model and leave the other properties unchanged
AutoMapper.Map<UpdatePlayerViewModel , PlayerEntity>(viewModel, player);
try
{
context.SaveChanges();
updateSuccessfull = true;
}
catch
{
updateSuccessfull = false;
}
}
However I am of the opinion that updating entity properties is a significant thing and shouldn't be done automatically. Others feel the same. Jimmy Bogard who created AutoMapper doesn't seem to believe it needs two way mapping (However he says that is partly as they built AutoMapper for their requirement) Similar answer here on Stackoverflow saying do it yourself.
It depends on the complexity of your application but I would look at using the command pattern to send a message to an appropriate handler containing your properties and have the handler update them. If it was successful we do one thing if it wasn't we do another. Same pattern is described in MVC in Action. See similar (here is the link)[http://www.paulstovell.com/clean-aspnet-mvc-controllers] and here is the second link