Error with EF core savecontext using Identity class - asp.net-core

I have a quiz sql schema and I am also using ASP.NET Identity. When I attempt to insert an answer from the user into the UserAnswer table I get the error below. It seems like it is trying to insert into the User table but I don't want that?
Violation of PRIMARY KEY constraint 'PK_AspNetUsers'. Cannot insert
duplicate key in object 'dbo.AspNetUsers'. The duplicate key value is
(71ddfebf-18ba-4214-a01e-42ca0f239804). Cannot insert explicit value
for identity column in table 'Questions' when IDENTITY_INSERT is set
to OFF. The statement has been terminated.
foreach (ProfileViewModel pvm in profileViewModels)
{
UserAnswer ua = new UserAnswer();
ua.QuestionId.ID = pvm.Question.ID;
ua.ApplicationUser.Id = userId;
ua.AnswerText = pvm.Answer;
_userAnswerRepository.Create(ua);
}
which just does
protected void Save() => _context.SaveChanges();
and the model is
public class UserAnswer
{
public UserAnswer()
{
this.QuestionId = new Question();
this.ApplicationUser = new ApplicationUser();
}
public int Id { get; set; }
public ApplicationUser ApplicationUser { get; set; }
public Question QuestionId { get; set; }
public string AnswerText { get; set; }
}

I guess I need to use virtual and not the actual object for some reason.. The model looked fine but it seems to confused the update
public class UserAnswer
{
public UserAnswer()
{
this.Question = new Question();
this.User = new ApplicationUser();
}
public int Id { get; set; }
public string UserId { get; set; } // FK to ApplicationUser
public int QuestionId { get; set; } // FK to Question
public string AnswerText { get; set; }
public virtual Question Question { get; set; }
public virtual ApplicationUser User { get; set; }
}

Related

Microsoft.EntityFrameworkCore.DbUpdateException

I have a comment table where it have a two foreign key(i.e Userid and postid). I was trying to insert data into comment table using these two foreign key but was unable to insert. This is my post table
public class Post
{
public int Id { get; set; }
public string PostText { get; set; }
public string Title { get; set; }
public bool Status { get; set; }
public DateTime PostDate { get; set; }
public virtual List<Comment> Comments { get; set; }
public ApplicationUser ApplicationUser { get; set; }
}
And this is my comment table
public class Comment
{
public int Id { get; set; }
public string CommentText { get; set; }
public DateTime CommentTime { get; set; }
public bool Status { get; set; }
public ApplicationUser CommentBy { get; set; }
public Post Posts { get; set; }
}
Comment service
public void Save(Comment comment)
{
_context.Set<Comment>().Add(comment);
_context.SaveChanges();
}
And this is my controller
[HttpPost]
public ObjectResult SaveComment([FromBody] Comment comment)
{
if (ModelState.IsValid)
{
try
{
_commentService.Save(comment);
return Ok("comment saved");
} catch (Exception e)
{
return BadRequest(e);
}
} else
{
return BadRequest("Model is not valid");
}
}
And the error is
{Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while updating the entries. See the inner exception for details. ---> System.Data.SqlClient.SqlException: Violation of PRIMARY KEY constraint 'PK_AspNetUsers'. Cannot insert duplicate key in object 'dbo.AspNetUsers'. The duplicate key value is (966fc417-8757-4bac-89b2-9975d4f2cd41).
Cannot insert explicit value for identity column in table 'Posts' when IDENTITY_INSERT is set to OFF.
The statement has been terminated.
this is my api request
The reason is that you will also insert a new comment.CommentBy when you're inserting a brand new comment:
// the `comment` here is constructed by model binding, which is a brand new entity
[HttpPost]
public ObjectResult SaveComment([FromBody] Comment comment)
{
// ...
_commentService.Save(comment); // save the brand new comment
// ...
}
"A brand new comment" means this Comment entity and its related propreties are all untracked. When saving a brand new entity, EF Core will also create related entities for you automatically.
To avoid this behavior, you could mark the state of comment.CommentBy as Unchanged,
_context.Entry(comment.CommentBy).State= EntityState.Unchanged;
so that the EF Core will not create a new CommentBy (i.e. an ApplicationUser) for you. But be careful: you must make sure the ApplicationUser already exists.
The same goes Post.
Another approach is much safer. As suggested by #Khai Nguyen in the comment, you should get ApplicationUser and Post instance from database, so that the EF Core knows there's already a ApplicationUser and a Post within database and won't insert new ApplicationUser or Post for you.

Petapoco can't update with non primary key identity

I am using AspNetIdentity and I have a non primary key column that is an identity auto increment.
[TableName("AspNetUsers")]
[PrimaryKey("Id", autoIncrement = false)]
public class Coach
{
public string Id { get; set; }
public string Email { get; set; }
public string UserName { get; set; }
public bool Active { get; set; }
public bool Admin { get; set; }
public int CoachId { get; set; }
}
How can I change my class definition to set CoachId to autoIncrement is false without it being the primary key? I'm using db.Save to save the object.
I just ended up executing a query!
var query = String.Format("UPDATE AspNetUsers SET Active = '{0}' WHERE Id='{1}'",activeStatus,id);

How to set Not Null and Unique key constraint on a property from mvc model

How can I apply not null and unique key constraint on a property from asp.net MVC model,
Below is my code:
public class Role
{
public int id { get; set; }
[Required]
[Index("RoelsIndex",IsUnique=true)]
public string Roles { get; set; }
}
Not sure what's your problem but Required and Index work fine when I try it.
public class Product
{
public int Id { get; set; }
[Required]
[Index(IsUnique = true)]
[MaxLength(400)]
public string Name { get; set; }
}
public class AppContext : DbContext
{
public DbSet<Product> Products { get; set; }
}

CodeFirst - Update single property

We are using EF5, Code First approach to an MVC4 app that we're building. We are trying to update 1 property on an entity but keep getting errors. Here's what the class looks like which the context created:
public partial class Room
{
public Room()
{
this.Address = new HashSet<Address>();
}
public int RoomID { get; set; }
public Nullable<int> AddressID { get; set; }
public Nullable<int> ProductVersionID { get; set; }
public string PhoneNumber { get; set; }
public string AltPhone { get; set; }
public string RoomName { get; set; }
public string Description { get; set; }
public string Comments { get; set; }
public string Notes { get; set; }
public virtual ICollection<Address> Address { get; set; }
}
Here's our ViewModel for the view:
public class RoomDetailsViewModel
{
//public int RoomID { get; set; }
public string RoomName { get; set; }
public string PhoneNumber { get; set; }
public string AltPhone { get; set; }
public string Notes { get; set; }
public string StateCode { get; set; }
public string CountryName { get; set; }
public string ProductVersion { get; set; }
public int PVersionID { get; set; }
public List<SelectListItem> ProductVersions { get; set; }
public Room Room { get; set; }
}
Here's the Controller Action being called on "Save":
[HttpPost]
public virtual ActionResult UpdateRoom(RoomDetailsViewModel model)
{
var db = new DBContext();
bool b = ModelState.IsValid;
var rooms = db.Rooms;
var rm = rooms.Where(r => r.RoomID == model.Room.RoomID).Single();
//List<Address> address = db.Addresses.Where(a => a.AddressID == rm.AddressID).ToList<Address>();
rm.ProductVersionID = model.PVersionID;
//rm.Address = address;
db.Entry(rm).Property(r => r.ProductVersionID).IsModified = true;
//db.Entry(rm).State = System.Data.EntityState.Modified;
db.SaveChanges();
return View("RoomSaved", model);
}
All this view does is display data and allow the user to change the Product Version (from a SelectList), so, in the Room Entity, all we are updating is the ProductVersionID property, nothing else. We can get the data to display properly but when we click "save", we get this error:
An object of type 'System.Collections.Generic.List`1[[Models.Address,
Web.Mobile.TestSite, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=null]]' cannot be set or removed from the Value
property of an EntityReference of type 'Models.Address'.
As you can see by the Controller Action, we've tried several different things but all seem to produce this error. I've tried to populate the model.Room.Address collection with an Address, without, but still get this error.
I read this StackOverflow article and this article as well but neither have solved my problem.
ANY help with this would be greatly appreciated!
After hours and hours of digging, turns out that EF did not import some of the PK's for my DB tables. What tipped me off to this was on the Room class, the PK RoomID did not have the [Key] attribute on it. I tried to reimport the table through the edmx but it never came through as a key (even though it's clearly marked PK in the DB). So, to get around it, I created a partial class of my DBContext and override the OnModelCreating event and included the key, like so:
public partial class DBContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Entity<Models.Room>().HasEntitySetName("Rooms");
modelBuilder.Entity<Models.Room>().HasKey(r => r.RoomID);
}
}
Once this was done, the Action saved the record as hoped.
I hope this helps someone else!

Entity Framework Creates New Record in Table I Didn't Reference when Inserting Into Other Table

In this website, users can register under a username and password, and can also post comments on articles. The models are pretty straightforward:
public class User
{
public int Id { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public bool IsAdmin { get; set; }
public DateTime JoinDate { get; set; }
public string AvatarPath { get; set; }
public string EmailAddress { get; set; }
}
public class ArticleComment
{
public int Id { get; set; }
public int ArticleId { get; set; }
public int UserId { get; set; }
public string CommenterName { get; set; }
public string Message { get; set; }
public DateTime CommentDate { get; set; }
public User User { get; set; }
}
Entity Framework correctly made the foreign key relationship between UserId on ArticleComment and Id on User when the database was created using code-first.
Here's my code for when a user posts a new comment:
public JsonResult SubmitComment(int articleId, string comment)
{
var response = new JsonResponse();
var currentUser = _userRepository.GetUserByUsername(User.Identity.Name);
//...
var newComment = new ArticleComment
{
ArticleId = articleId,
CommentDate = DateTime.Now,
CommenterName = currentUser.Username,
UserId = currentUser.Id,
User = currentUser,
Message = comment,
};
try
{
_articleRepository.Insert(newComment);
}
catch (Exception e)
{
response.Success = false;
response.AddError("newComment", "Sorry, we could not add your comment. Server error: " + e.Message);
return Json(response);
}
response.Success = true;
response.Value = newComment;
return Json(response);
}
The values that make up the newComment object all appear to be correct, and the Insert method in my Article repository class is straight and to the point:
public void Insert(ArticleComment input)
{
DataContext.ArticleComments.Add(input);
DataContext.SaveChanges();
}
But once this happens, poof: a new record in my Users table appears along with the new record in ArticleComments. All of the info in the new Users record is duplicated from that user's existing record - the only difference is the value for the primary key Id. What gives?
In addition to my comment, you need to make sure that both _userRepository and _articleRepository are using the same DbContext instance.
Either that, or you can try this:
var newComment = new ArticleComment
{
ArticleId = articleId,
CommentDate = DateTime.Now,
CommenterName = currentUser.Username,
UserId = currentUser.Id,
// User = currentUser, let the UserId figure out the User, don't set it yourself.
Message = comment,
};