I have these two models:
UserModel
[Table("user")]
public class UserModel {
[Key]
[Column("emailaddress")]
public string Emailaddress { get; set; }
[Column("firstname")]
public string Firstname { get; set; }
[Column("lastname")]
public string Lastname { get; set; }
}
ContactPersonModel
[Table("contactperson")]
public class ContactPersonModel {
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
[Column("firstname")]
public string Firstname { get; set; }
[Column("lastname")]
public string Lastname { get; set; }
[Column("emailaddress")]
[EmailAddress]
[Index(IsUnique = true)]
[MaxLength(255)]
public string Emailaddress { get; set; }
[Column("phonenumber")]
[Phone]
public string Phonenumber { get; set; }
public virtual UserModel Creator { get; set; }
}
This is the method I use to insert items in the database:
public async Task<ContactPersonModel> AddContactPerson(ContactPersonModel model) {
dbmodel.ContactPerson.Add(model);
dbmodel.Entry(model.Creator).State = EntityState.Unchanged;
if (await dbmodel.SaveChangesAsync() == 0) {
Log.ErrorFormat("cannot add contactperson {0}", model.Emailaddress);
throw new Exception("cannot add contactperson");
} else {
await dbmodel.Entry(model).ReloadAsync();
return model;
}
}
When I call the method AddContactPerson the properties Firstname, Lastname and Emailaddress get copied from the UserModel to the ContactPersonModel and overrides the values I set. How can I prevent this behavior?
Related
I have 2 models. Client and AgentUser. Client is just a normal EF model and AgentUser is an Identity model. Client has a foreign key of AgentUser. When I create a new instance of Client and set the property to an instance of AgentUser and save it to database, it produces and SQL Exception.
AgentUser.cs
public class AgentUser : IdentityUser
{
[Required]
[MaxLength(100)]
public string FirstName { get; set; } = string.Empty;
[Required]
[MaxLength(100)]
public string LastName { get; set; } = string.Empty;
[Required]
[MaxLength(100)]
public string AgentType { get; set; } = string.Empty;
public string? ReferrerId { get; set; }
public virtual AgentUser Referrer { get; set; }
public virtual List<AgentUser> Referrals { get; set; }
public virtual List<Client> Clients { get; set; }
}
Client.cs
public class Client
{
public int ClientId { get; set; }
[Required]
[MaxLength(100)]
public string Company { get; set; }
[Required]
[MaxLength(100)]
public string FirstName { get; set; }
[Required]
[MaxLength(100)]
public string LastName { get; set; }
[DataType(DataType.EmailAddress)]
public string? Email { get; set; }
[Phone]
public string? PhoneNumber { get; set; }
[MaxLength(100)]
public string? Address { get; set; }
[MaxLength(100)]
public string? City { get; set; }
[MaxLength(100)]
public string? State { get; set; }
[MaxLength(6)]
public string? ZipCode { get; set; }
[DataType(DataType.Date)]
public DateTime DateAdded { get; set; }
public string? ReferrerId { get; set; }
public virtual AgentUser Referrer { get; set; }
}
Razor Page handler for saving Client instance to database:
public async Task<IActionResult> OnPostAsync(string? returnUrl = null)
{
returnUrl ??= Url.Content("~/Member/Clients/Index");
if (ModelState.IsValid)
{
Client newClient = new Client()
{
Company = Input.Company,
FirstName = Input.FirstName,
LastName = Input.LastName,
Email = Input.Email,
PhoneNumber = Input.PhoneNumber,
Address = Input.Address,
City = Input.City,
State = Input.State,
ZipCode = Input.ZipCode,
DateAdded = DateTime.UtcNow.Date
};
if (Input.ReferrerId != null)
{
AgentUser referrer = await _userManager.FindByIdAsync(Input.ReferrerId);
if (referrer == null)
{
ModelState.AddModelError(string.Empty, $"There is no agent with the id: {Input.ReferrerId}");
return Page();
}
newClient.Referrer = referrer;
}
await _context.Clients.AddAsync(newClient);
await _context.SaveChangesAsync();
return RedirectToPage(returnUrl);
}
return Page();
}
SQL Exception:
SqlException: The INSERT statement conflicted with the FOREIGN KEY
SAME TABLE constraint "FK_AgentUser_AgentUser_ReferrerId". The
conflict occurred in database "mydb", table "dbo.AgentUser",
column 'Id'. The statement has been terminated.
In ASP.NET Core MVC, I am using code first migration. I have these two models:
Models:
public class User
{
public int Id { get; set; }
public string Email { get; set; }
public string Password { get; set; }
}
public class Student
{
[Key]
public int Id { get; set; }
[Required]
[StringLength(20)]
public string FirstName { get; set; }
[Required]
[StringLength(20)]
public string LastName { get; set; }
[Required]
[StringLength(40)]
public string Guardian { get; set; }
[Required]
public DateTime DateOfBirth { get; set; }
[EmailAddress]
[Required]
public string Email { get; set; }
public bool AdminPermition { get; set; }
}
Then the two are in a single ViewModel:
ViewModel:
public class StudentRegisterModel
{
[Required]
[StringLength(20)]
public string FirstName { get; set; }
[Required]
[StringLength(20)]
public string LastName { get; set; }
[Required]
[StringLength(40)]
public string Guardian { get; set; }
[Required]
public DateTime DateOfBirth { get; set; }
[EmailAddress]
[Required]
public string Email { get; set; }
[Required]
public string Password { get; set; }
[Required]
public string ConfirmPassword { get; set; }
}
Everything is saved using this service:
Service:
public async Task<bool> RegistrationService(StudentRegisterModel registerModel)
{
try
{
//validation functions
var context = new ValidationContext(registerModel, serviceProvider: null, items: null);
var results = new List<ValidationResult>();
if (Validator.TryValidateObject(registerModel, context, results, true))
{
if (CheckEmailAvailability(registerModel.Email)){
if (registerModel.Password != registerModel.ConfirmPassword)
return false;
Student student = new Student
{
FirstName = registerModel.FirstName,
LastName = registerModel.LastName,
Email = registerModel.Email,
Guardian = registerModel.Guardian,
DateOfBirth = registerModel.DateOfBirth,
AdminPermition = false
};
User user = new User
{
Email = registerModel.Email,
Password = Encoder(registerModel.Password),
};
_context.Add(student);
_context.Add(user);
await _context.SaveChangesAsync();
return true;
}
}
return false;
}
catch
{
return false;
}
}
The Id in User is auto-generated, while the Id in Student is not.
How do I automatically duplicate the Id in User into the Id in Student?
Thanks
I think something like this should work:
public class User
{
[Key]
public int Id { get; set; }
[InverseProperty("Student")]
public Student Student { get; set; }
// ...
}
public class Student
{
[Key]
public int Id { get; set; }
[ForeignKey("Id")]
public User User { get; set; }
// ...
}
In my HomeController, I am having trouble with my create function accessing the database. After submitting the form in my browser, this is the error that shows:
Error Given
MySqlException: Cannot add or update a child row: a foreign key constraint fails (petshelterdb.pets, CONSTRAINT FK_Pets_Owners_OwnerId FOREIGN KEY (OwnerId) REFERENCES owners (OwnerId) ON DELETE CASCADE)
MySqlConnector.Core.ResultSet.ReadResultSetHeaderAsync(IOBehavior ioBehavior) in ResultSet.cs, line 49
I am not using a login/registration. The idea is that I have a "bulletin board" that shows pets that can be adopted and owners that can adopt. A new pet or owner can be added to the board. If I select the owner's name, I can have that owner "adopt" a pet on the board. I designated in the HomeController code which line is the issue.
Since I'm not working with a UserId, I'm not sure how to go about this.
Pet.cs
namespace petShelter.Models
{
public class Pet
{
[Key]
public int PetId { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Type { get; set; }
[Required]
public string Description { get; set; }
public string Skill1 { get; set; }
public string Skill2 { get; set; }
public string Skill3 { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime UpdatedAt { get; set; }
public Owner Owner { get; set; }
public int OwnerId { get; set; }
}
}
Owner.cs
namespace petShelter.Models
{
public class Owner
{
[Key]
public int OwnerId { get; set; }
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime UpdatedAt { get; set; }
List<Pet> MyPets { get; set; }
public string FullName()
{
return FirstName + " " + LastName;
}
}
}
HomeController.cs
[HttpPost("/pet/new")]
public IActionResult Create(Pet newPet)
{
if (ModelState.IsValid)
{
_context.Add(newPet);
_context.SaveChanges(); ***THIS IS WHERE ISSUE OCCURS***
return RedirectToAction("Index", new { id = newPet.PetId });
}
else
{
if (newPet.Name == null)
{
ModelState.TryAddModelError("Name", "The Name field is required");
}
return View("NewPet", newPet);
}
}
PetShelterContext.cs
namespace petShelter.Models
{
public class PetShelterContext : DbContext
{
public PetShelterContext(DbContextOptions options) : base(options) { }
public DbSet<Pet> Pets { get; set; }
public DbSet<Owner> Owners { get; set; }
}
}
Replace
public int OwnerId { get; set; }
with
public int? OwnerId { get; set; }
and fix properties ( the attributes are optional for net5)
public class Owner
{
.......
[InverseProperty(nameof(Pet.Owner))]
public virtual ICollection<Pet> Pets { get; set; }
.....
}
and maybe here too
public class Pet
{
.....
public int OwnerId { get; set; }
[ForeignKey(nameof(OwnerId))]
[InverseProperty("Pets")]
public Owner Owner { get; set; }
}
When I send from Microsoft sql server to database then work fine.
But, when send post request from postman or angular, foreign data always is null.
I don't know where is problem.
This is class:
public class Korpa
{
public int Id { get; set; }
public int Id_korisnika { get; set; }
public Korisnik Korisnik { get; set; }
public int Id_Artikla { get; set; }
public Artikal Artikal { get; set; }
}
public class Artikal
{
public int Id { get; set; }
[Required(ErrorMessage = "Unesite naziv grupe artikla!")]
[StringLength(255)]
public string Grupa { get; set; }
[Required(ErrorMessage = "Unesite ime artikla!")]
[StringLength(255)]
public string Naziv_artikla { get; set; }
public decimal? Nabavna_cena { get; set; }
public decimal? Prodajna_cena { get; set; }
public short? kolicina { get; set; }
public string url_slike { get; set; }
public string Specifikacija { get; set; }
}
public class Korisnik
{
public int Id { get; set; }
[Required(ErrorMessage = "Unesite vase ime!")]
[StringLength(255)]
public string Ime { get; set; }
[Required(ErrorMessage = "Unesite vase prezime!")]
[StringLength(255)]
public string Prezime { get; set; }
[Required(ErrorMessage = "Unesite korisnicko ime!")]
[StringLength(255)]
public string Username { get; set; }
[Required(ErrorMessage = "Unesite sifru!")]
[StringLength(255)]
public string Sifra { get; set; }
[Required(ErrorMessage = "Unesite email")]
[StringLength(255)]
public string Email { get; set; }
[Required(ErrorMessage = "Unesite vasu adresu!")]
[StringLength(255)]
public string Adresa { get; set; }
[Required(ErrorMessage = "Unesite vas broj telefona!")]
[StringLength(255)]
public string Broj_telefona { get; set; }
public string jmbg { get; set; }
public int Nivo { get; set; }
}
This cotroller:
// GET: api/Korpas/5
[ResponseType(typeof(Korpa))]
public IHttpActionResult GetKorpa(int id)
{
var korpa = db.Korpa
.Include(c => c.Korisnik)
.Include(c => c.Artikal)
.SingleOrDefault(c => c.Id == id);
if (korpa == null)
{
return NotFound();
}
return Ok(korpa);
}
// POST: api/Korpas
[ResponseType(typeof(Korpa))]
public IHttpActionResult PostKorpa(Korpa korpa)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.Korpa.Add(korpa);
db.SaveChanges();
return CreatedAtRoute("DefaultApi", new { id = korpa.Id }, korpa);
}
Where is null, this send data from post request, where is not, then send sql query from ms sql server
SOLVED
public class Korpa
{
public int Id { get; set; }
public int Id_korisnika { get; set; }
[ForeignKey("Id_korisnika")]
public Korisnik Korisnik { get; set; }
public int Id_Artikla { get; set; }
[ForeignKey("Id_Artikla")]
public Artikal Artikal { get; set; }
}
Just add [ForeignKey("name of foreign key")]
Your POST method receives a Korpa model, but the entity does not have the Artikal_Id property, you must add the property to the Korpa model so that the web api can perform the serialization.
public class Korpa
{
public int Id { get; set; }
public int Id_korisnika { get; set; }
public Korisnik Korisnik { get; set; }
public int Id_Artikla { get; set; }
public Artikal Artikal { get; set; }
public int Artikal_Id {get; set;} // Add this property
}
I have a base entity class which is derived by two class, named as Student and Department.
public abstract class Entity
{
[Key]
public string Id { get; set; }
[Required]
public DateTime Created { get; set; }
[Required]
public string CreatedBy { get; set; }
[Required]
public DateTime Modified { get; set; }
[Required]
public string ModifiedBy { get; set; }
}
public class Department : Entity
{
[Required]
[Index]
[StringLength(128)]
public string Name { get; set; }
public virtual ICollection<Student> Students { get; set; }
}
public class Student : Entity
{
[Required]
[Index]
[StringLength(128)]
public string Name { get; set; }
public string Phone { get; set; }
[Required]
public string DepartmentId { get; set; }
[ForeignKey("DepartmentId")]
public virtual Department Department { get; set; }
}
Now I want to instantiate the derived classes but don't want to duplicate the common initialization codes. I have used ref out etc ways, but it is getting build errors.
public Student CreateStudent()
{
Student student = new Student
{
Name = nameTextBox.Text,
Phone = phoneTextBox.Text,
DepartmentId = departmentComboBox.SelectedValue.ToString()
};
SetCommonValues(ref student);
return student;
}
public Department CreateDepartment()
{
Department department=new Department()
{
Name = nameTextBox.Text
};
SetCommonValues(ref department);
return department;
}
public void SetCommonValues(ref Entity entity)
{
entity.Id = Guid.NewGuid().ToString();
entity.Created = DateTime.Now;
entity.Modified = DateTime.Now;
entity.CreatedBy = Constants.UserName;
entity.ModifiedBy = Constants.UserName;
}
Any suggestion will be highly appreciated.
I'm probably missing something here. Is there any particular reason you are not opting for a constructor in the abstract class like the following?
public abstract class Entity
{
public string Id { get; set; }
public DateTime Created { get; set; }
public string CreatedBy { get; set; }
public DateTime Modified { get; set; }
public string ModifiedBy { get; set; }
public Entity()
{
this.Id = Guid.NewGuid().ToString();
this.Created = DateTime.UtcNow;
this.Modified = this.Created;
}
public Entity(string createdBy, string modifiedBy) : this()
{
this.CreatedBy = createdBy;
this.ModifiedBy = modifiedBy;
}
}
public class Department : Entity
{
public string Name { get; set; }
public virtual ICollection<Student> Students { get; set; }
}
public class Student : Entity
{
public string Name { get; set; }
public string Phone { get; set; }
public string DepartmentId { get; set; }
public virtual Department Department { get; set; }
}
Solved using Extension Method architecture
Modified caller method
public Student CreateModel()
{
Student model = new Student
{
Name = nameTextBox.Text,
Phone = phoneTextBox.Text,
DepartmentId = departmentComboBox.SelectedValue.ToString(),
};
model.SetCommonValues();
return model;
}
And the SetCommonValues method is
public static Entity SetCommonValues(this Entity entity)
{
entity.Id = Guid.NewGuid().ToString();
entity.Created = DateTime.Now;
entity.Modified = DateTime.Now;
entity.CreatedBy = Constants.UserName;
entity.ModifiedBy = Constants.UserName;
return entity;
}
I could mark the Extension Method as void, but for extensibility, I returned the object.