Cannot Insert new Data in the Database in .NET Core API error Database operation - sql-server

I am working on an API and when I started adding new data. I received this error. It was working when I manually add the ID every input but now I got this error and after adding some solutions from here its still not working.
Error:
Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException: Database operation expected to affect 1 row(s) but actually affected 0 row(s).
Data may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=527962 for information on understanding and handling optimistic concurrency exceptions.
Code for insert:
public bool Insert(string UserName, SendInventoryModel sendInventoryModel)
{
using (DatabaseContext context = new DatabaseContext())
{
bool flag = false;
// Create new
InventoryEntity inventoryEntity = new InventoryEntity
{
UserName = sendInventoryModel.UserName,
Item = sendInventoryModel.Item ,
};
context.Table.Add(inventoryEntity);
context.SaveChanges();
// Check
var model = CheckUserNameID(UserName, sendInventoryModel.Item);
var data = context.Table.Find(model.Id);
if (null != data)
{
flag = true;
}
return flag;
}
}
SendInventoryModel:
public class SendSiteMailModel
{
[Required]
public string UserName { get; set; }
[Required]
public string Item{ get; set; }
}
InventoryController:
[HttpPost("{username}")]
[Authorize]
public JObject Post([Required] string UserName, [FromBody] SendInventoryModel sendInventoryModel)
{
ResponseModel x = new ResponseModel();
try
{
InventoryRepository InventoryRepository = new InventoryRepository();
bool isSuccess = InventoryRepository.Insert(UserName, sendInventoryModel);
}
catch (Exception error)
{
// if not successful
}
return Json(x);
}
I already added [DatabaseGenerated(DatabaseGeneratedOption.Identity)] in my InventoryEntity and InventoryModel.
InventoryEntity:
[Key]
DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
InventoryModel:
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
I also added the below code in my DBContext.cs:
public virtual DbSet<OtherTableEntity> Table{ get; set; }
public virtual DbSet<InventoryEntity> Table{ get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<OtherTableEntity>();
modelBuilder.Entity<InventoryEntity>().Property(x => x.Id).ValueGeneratedOnAdd();
base.OnModelCreating(modelBuilder);
}
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
Add finally my table design: Inventory ID:
(Is Identity) = Yes
Identity Increment = 1
Identity Seed = 1
Note that there is no Primary Key in the Inventory table. And its an old table with existing data. The current database was migrated from membership to identity.
After all the things that I have added the context.SaveChanges(); in the insert method still does not work. Any ideas or suggestion on how to fix this problem?
Note: I've changed the table entity names and models per Asherguru suggestion since its kinda confusing and generic.

Are your TableEntity and Table in database same table names?
Why different names - TableEntity and Table?
Try to add [Table("YourTableNameInDatabase")] in TableEntity class. Then EF can find actual table in database and insert into this table.
[Table("YourTableNameInDatabase")]
public partial class TableEntity
{
public int Id { get; set; }
}
It would be less confusing if you show actual table names with some necessary screenshots.

Related

Is there a way to take First() from a hierarchy table in Entity Framework Core?

Is there any way to access a table that is a hierarchy?
Entity Framework Core returns null from the First() method, the table is NOT empty. I use SQL Server to store the table.
public class TestProjectEFDbContext : DbContext
{
private const string connectionString = #"data source=DESKTOP-I2JBLKP; Initial Catalog=TestProjectEF; Trusted_Connection=True; ";
public TestProjectEFDbContext() { }
public TestProjectEFDbContext(DbContextOptions options) : base(options) { }
public DbSet<University> Universities { get; set; }
public DbSet<MedicineUniversity> MedicineUniversities { get; set; }
public DbSet<ArtUniversity> ArtUniversities { get; set; }
public DbSet<TechUniveristy> TechUniveristies { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(connectionString);
}
}
var FirstUniversity = testProjectEFDbContext.Universities.First(); // throws an error
The InvalidOperationException: Sequence contains no elements When appeared that you have not any records in the mapped table.
And it is disappeared when you use FirstOrDefault() extension method.
So, double-check the database and table that you are using in the connection string and you have checked that have records.
Also, beware of Table Attribute: [Table(string name, Properties:[Schema = string])

Null data returned using a 1:1 model

I have two SQL tables, User and UserType joined with UserType as a foreign key, with their respective models in ASP. To my understanding, this should be a 1:1 relationship (correct me if I'm wrong). One unique user, set as a type of user (being admin, super admin, user etc).
When I try and retrieve a list of users, it returns a null on the property UserType.
I used Google to get this far, but I'm struggling to get this particular issue fixed.
At one point I got an error stating: "Unable to determine the principal end of an association". To get around that, I included a Required annotation (didn't work) and a ForeignKey annotation (didn't work either) in both models, both simultaneously and separately.
This is what I have so far.
[Table("Users", Schema = "dbo")]
public class Users
{
[Key, ForeignKey("UserType")]
public Guid Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string ContactNumber { get; set; }
public UserType UserType { get; set; }
public string IsActive { get; set; }
}
[Table("UserType", Schema = "dbo")]
public class UserType
{
[Key]
public Guid Id { get; set; }
public string Type { get; set; }
public string Description { get; set; }
public string IsActive { get; set; }
public Users Users { get; set; }
}
I'm using the below LINQ method to retrieve the data:
public PagedTables<Users> GetAllUsers(Pagination pagination)
{
using (var db = new DbContext())
{
var user = new PagedTables<Users>()
{
Data = db.Users.OrderBy(U => U.Id).Skip(pagination.Page).Take(pagination.Limit).ToList(),
Count = db.Users.Count()
};
return user;
}
}
A break point on the users var shows that the property UserType returns null. I would expect the assigned user type to be joined onto the user.
Any help would be appreciated. Thanks
My EF background is database-first but if you are eager loading (i.e. not lazy loading) then are you missing an Include to tell LINQ to go and get the UserType? Something like;
Data = db.Users.OrderBy(U => U.Id).Skip(pagination.Page).Take(pagination.Limit).Include(U => U.UserType).ToList(),

Entity Framework auto assign FK to reference Entity during insertion?

Could you please explain for me Why and How EF auto assign FK to reference entity when i insert entities into Database? I got these simple Entities like this:
First one is Catalogue
public class Catalogue
{
public int CatalogueId { get; set; }
public string Name { get; set; }
public ICollection<Page> Pages { get; set; }
}
Second one is Page which reference to Catalogue.
public class Page
{
public int PageId { get; set; }
public string Name { get; set; }
public int CatalogueId { get; set; }
public Catalogue Catalogue { get; set; }
}
The relationship in this case is one to many. So in the code i am using this:
using (var context = new MyDbContext())
{
var catalogue = new Catalogue
{
Name = "catalogue 1"
};
var page = new Page
{
Name = "page 1",
CatalogueId = 0
};
context.Catalogues.Add(catalogue);
context.Pages.Add(page);
context.SaveChanges();
}
The MyDbContext is simple nothing special.
When i run this code i am expecting it will generate an error because CatalogueId = 0 is not valid, but it working fine,.
It is interesting me and hopefully someone can clarify that :).
Thanks in advance
This is how EF work under the hood. The context will go and execute the INSERT and generate the update for the FK value in the table. Later, will populate the tracked entity with the real key value.
You can experiment with unattached entities and will notice that no FK value is updated.

Cannot save multiple files to database with Foreign Key

In my MVC application I have two tables called Ticket and Attachment and I want to save attachments for per ticket. The problem is that: I need to save multiple attachments with the TicketID when creating a new ticket. So, I think I should create a new ticket in the Ticket table and then get its ID and save all the attachments with this TicketID to the Attachment table in a loop. I have look at many web sites and stackoverflow, but there is not such a kind of problem or solution on that pages. Any idea?
Note: I use Entity Framework Code First, but I can also use Stored Procedure or SQL command for this operation.
Here are these two models:
public class Ticket
{
[Key]
public int ID { get; set; }
public string Description { get; set; }
//... removed for clarifty
}
public class Attachment
{
[Key]
public int ID { get; set; }
//Foreign key for Ticket
public int TicketID { get; set; }
public byte[] FileData { get; set; }
public string FileMimeType { get; set; }
}
And the controller method:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Exclude = null)] TicketViewModel viewModel
/* contains both model: Ticket and Attachment */, IEnumerable<HttpPostedFileBase> files)
{
if (ModelState.IsValid)
{
//??? First I need to save Ticket
repository.SaveTicket(viewModel.Ticket);
foreach(var f in files)
{
viewModel.Attachment.FileMimeType = f.ContentType;
viewModel.Attachment.FileData = new byte[f.ContentLength];
f.InputStream.Read(viewModel.Attachment.FileData , 0, f.ContentLength);
//??? Then save all attachment. But no idea how to get TicketID
repository.SaveAttachment(viewModel.Attachment);
}
}
return View();
}
The ID property will be automatically filled by EF after a SaveChanges. Your code can then use it. I assume that the viewModel.Ticket object is the actual object saved to the database. If not, please also post the SaveTicket method.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Exclude = null)] TicketViewModel viewModel
/* contains both model: Ticket and Attachment */, IEnumerable<HttpPostedFileBase> files)
{
if (ModelState.IsValid)
{
// assumes viewModel.Ticket is the actual entity saved, and SaveChanges is called.
repository.SaveTicket(viewModel.Ticket);
foreach(var f in files)
{
viewModel.Attachment.FileMimeType = f.ContentType;
viewModel.Attachment.FileData = new byte[f.ContentLength];
f.InputStream.Read(viewModel.Attachment.FileData , 0, f.ContentLength);
// fill ticket id
viewModel.Attachment.TicketID = viewModel.Ticket.ID;
repository.SaveAttachment(viewModel.Attachment);
}
}
return View();
}
If you want to do everything in one transaction, you can add the childs immediatly, and SaveChanges will save all objects:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Exclude = null)] TicketViewModel viewModel
/* contains both model: Ticket and Attachment */, IEnumerable<HttpPostedFileBase> files)
{
if (ModelState.IsValid)
{
var ticket = viewModel.Ticket;
foreach(var f in files)
{
var attachment = new Attachment();
attachment.FileMimeType = f.ContentType;
attachment.FileData = new byte[f.ContentLength];
f.InputStream.Read(attachment.FileData , 0, f.ContentLength);
ticket.Attachments.Add(attachment);
}
// this will save the ticket and attachments
repository.SaveTicket(ticket);
}
return View();
}
Your Ticket class will have to look like this:
public class Ticket
{
[Key]
public int ID { get; set; }
public string Description { get; set; }
// EF will now to use the foreign key to the attachment table
public virtual ICollection<Attachment> Attachments { get; set; }
}

Update model in database using entity framework gives conflict with foreign key

I know this has been asked millions of times and I've had it myself hundreds of times, but for some reason I can't fix this one.
I get the well known error:
The UPDATE statement conflicted with the FOREIGN KEY constraint ...
All my tables in my database are cascaded when an insert or delete is done.
Now on to the error:
I want to update an admins table (administrator accounts) that is linked to a cultures table (for languages).
Everything is filled in correctly. and thus we get to the following code:
[HttpPost]
public ActionResult Edit(Admins admins)
{
if (!ModelState.IsValid)
{
return View(admins);
}
admins.cultures_id = admins.Cultures.id;
_unitOfWork.AdminsRepository.Update(admins);
_unitOfWork.Save();
return RedirectToAction("Index", "Overview", new { area = "Admin" });
}
I first set the cultures id of my admin object/entity equal to that of the id in the cultures table that is linked:
admins.cultures_id = admins.Cultures.id;
I then fill update the table:
_unitOfWork.AdminsRepository.Update(admins);
The method update holds this code:
public virtual void Update(TEntity entityToUpdate)
{
DbSet.Attach(entityToUpdate);
ArtWebShopEntity.Entry(entityToUpdate).State = EntityState.Modified;
}
So far so good, but then, when I actually want to save the admin:
_unitOfWork.Save();
That save method holds this code:
public void Save() {
try
{
_artWebshopEntity.SaveChanges();
}
catch (DbEntityValidationException dbEx)
{
foreach (var validationErrors in dbEx.EntityValidationErrors)
{
Console.WriteLine("Entity of type \"{0}\" in state \"{1}\" has the following validation errors:", validationErrors.Entry.Entity.GetType().Name, validationErrors.Entry.State);
foreach (var validationError in validationErrors.ValidationErrors)
{
Console.WriteLine("- Property: \"{0}\", Error: \"{1}\"", validationError.PropertyName, validationError.ErrorMessage);
}
}
throw; // Will do something here later on...
}
}
And at the SaveCHanges method I get the error. I know what it means but I can't seem to fix it. I've tried all the things I know that could cause it.
Edit
I only want to update the admin values, so I don't want to update the culture values.
This is the query:
update [dbo].[Admins]
set [login] = 'Herve' /* #0 */,
[password] = null,
[salt] = null,
[email] = 'xxxxx.xxx#glevin.be' /* #1 */,
[permissions] = 'administrator' /* #2 */,
[attempts] = 4 /* #3 */,
[locked] = 0 /* #4 */,
[cultures_id] = 0 /* #5 */
where ([id] = 1 /* #6 */)
So, the cultures_id is the issue. I've now did the following:
var updateAdmin = new Admins
{
attempts = admins.attempts,
cultures_id = admins.cultures_id,
email = admins.email,
locked = admins.locked,
login = admins.login,
id = admins.id,
password = admins.password,
permissions = admins.permissions,
salt = admins.salt,
};
And that works, but the moment I add the Cultures object to the mix, it crashes and gives me the reference error. So it boils down to, how the frack do I update a table with a foreign key to another table to also needs to be updated?
Edit II
My admin and cultures entity (database first), also image of database in sql management studio:
Admin class:
public partial class Admins
{
public int id { get; set; }
public string login { get; set; }
public string password { get; set; }
public string salt { get; set; }
public string email { get; set; }
public string permissions { get; set; }
public Nullable<int> attempts { get; set; }
public Nullable<bool> locked { get; set; }
public Nullable<int> cultures_id { get; set; }
public virtual Cultures Cultures { get; set; }
}
Cultures class:
public partial class Cultures
{
public Cultures()
{
this.Categories_local = new HashSet<Categories_local>();
this.Menu_items_local = new HashSet<Menu_items_local>();
this.Products_local = new HashSet<Products_local>();
this.Subcategories_local = new HashSet<Subcategories_local>();
this.Webpages_local = new HashSet<Webpages_local>();
this.Admins = new HashSet<Admins>();
}
public int id { get; set; }
public string name { get; set; }
public string display_name { get; set; }
public virtual ICollection<Categories_local> Categories_local { get; set; }
public virtual ICollection<Menu_items_local> Menu_items_local { get; set; }
public virtual ICollection<Products_local> Products_local { get; set; }
public virtual ICollection<Subcategories_local> Subcategories_local { get; set; }
public virtual ICollection<Webpages_local> Webpages_local { get; set; }
public virtual ICollection<Admins> Admins { get; set; }
}
I've gotten it to work!
The problem was that in the edit page the final field was the field that showed the name of the culture that corresponded with the id of the admin.
In other words I did the following:
#Html.EditorFor(model => model.Cultures.name)
But this wasn't the correct way.
In order to show the name of the culture but in the code pass the culture id, I used a #Html.DropDownListFor()-element.
The problem with this however was that my original model, Admins, didn't have a IEnumerable object that I could pass to the dropdownlist element in my view. I had to create a new model which I named CreateAdminModel, The new model looks like this:
public class CreateAdminModel
{
public CreateAdminModel() { }
public CreateAdminModel(IEnumerable<SelectListItem> cultures) { Cultures = cultures; }
public CreateAdminModel(Admins admin) { Admin = admin; }
public CreateAdminModel(IEnumerable<SelectListItem> cultures, Admins admin)
{
Cultures = cultures;
Admin = admin;
}
public IEnumerable<SelectListItem> Cultures { get; set; }
public Admins Admin { get; internal set; }
}
It has an Admin object created by the entity framework (database first).
With that new model I created the following method:
private CreateAdminModel CreateAdminWithcultureDetails(Admins admin = null)
{
var cultureItems = (_unitOfWork.CulturesRepository.Get()).ToArray();
var cultureList = new List<SelectListItem>();
for (int i = 0; i < cultureItems.Count(); i++) cultureList.Add(new SelectListItem { Text = cultureItems[i].name, Value = cultureItems[i].id.ToString() });
return admin != null ? new CreateAdminModel(cultureList, admin) : new CreateAdminModel(cultureList);
}
This fills the dropdown list with the cultures and depending on whether or not an admin object was passed also adds an admin object.
Now I can use this model in the view and correctly fill both the dropdown list and the admin if necessary.
I'm going to do the same for the other things that have to use CRUD.

Resources