How to replicate autogenerated primary key into another table - c#

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; }
// ...
}

Related

EF Core SQL Exception in saving a model with a foreign key of an Identity

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.

Send post request with foreign key - controller set null for foreign data

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
}

Cannot implicitly convert type 'System.Collections.Generic.List<int>' to 'System.Collections.Generic.IEnumerable<Model>'

When using Select() I am getting this error
Cannot implicitly convert type 'System.Collections.Generic.List<int>' to 'System.Collections.Generic.IEnumerable<OgrenciEvi.Areas.Message.Models.MessageModel>'.
SiteContext db = new SiteContext();
[Route]
public ActionResult Index()
{
var model = new ViewModel();
int UserID = int.Parse(User.Identity.GetID());
model.Messages = db.Message.Where(m => m.ReceiverID == UserID || m.SenderID == UserID).Select(m=>m.SenderUser.Name).ToList();
return View(model);
}
How I fix it ?
Edit:
public class MessageModel
{
[Key]
public int MessageID { get; set; }
[Required(ErrorMessage = "Boş mesaj gönderilemez.")]
public string MessageContent { get; set; }
[Required]
public int SenderID { get; set; }
[Required]
public int ReceiverID { get; set; }
[Required]
public DateTime SendingDate { get; set; }
[Required]
public bool IsSeen { get; set; }
public virtual UserModel SenderUser { get; set; }
public virtual UserModel ReceiverUser { get; set; }
MessageModel() {
SendingDate = DateTime.Now;
}
}
userModel:
public class UserModel
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public int UserID { get; set; }
[Required (ErrorMessage ="İsim alanı boş geçilemez.")]
public string Name { get; set; }
[Required(ErrorMessage = "Soyadı alanı boş geçilemez.")]
public string Surname { get; set; }
[RegularExpression(#"^([a-zA-Z0-9_\-\.]+)#((\[[0-9]{1,3}" +
#"\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\" +
#".)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$",
ErrorMessage = "E-Posta adresi geçersiz.")]
[DataType(DataType.EmailAddress)]
public string Mail { get; set; }
[DataType(DataType.Password)]
public string Password { get; set; }
[NotMapped] // Does not effect with your database
public string ConfirmPassword { get; set; }
public int Gender { get; set; }
[RegularExpression("^[0-9]*$", ErrorMessage ="Telefon numarası geçersiz.")]
public string PhoneNumber{ get; set; }
public int SmokeStatus { get; set; }
public DateTime RegistrationDate { get; set; }
[HiddenInput(DisplayValue = false)]
public string ReturnUrl{ get; set; }
[Range(1900,2000, ErrorMessage ="Doğum yılı 1900 ile 2000 yılları arasında olmalı.")]
[Required(ErrorMessage ="Yaş alanı boş geçilemez.")]
public int BirthYear { get; set; }
public string FacebookID { get; set; }
public bool Manager { get; set; }
public int AccessFacebook { get; set; }
public int AccessInstagram { get; set; }
public int AccessPhoneNumber { get; set; }
public int AccessTwitter { get; set; }
public List<LookingForaMateModel> LFMate { get; set; }
public List<LookingForaHome> LFHome { get; set; }
public List<AlbumModel> Album { get; set; }
public List<PropertyTransferModel> PropertyTransfer{ get; set; }
[ForeignKey("SenderID")]
public List<MessageModel> SenderUser { get; set; }
[ForeignKey("ReceiverID")]
public List<MessageModel> ReceiverUser { get; set; }
public UserModel() {
RegistrationDate = DateTime.Now;
}
}
I want "direct message" for my web site and the design look like facebook messenger so there is a panel on left side. I should get list Message's sender name and last message. But I couldn't make it :)
You still havn't shown your code for the ViewModel class. But Assuming that model.Messages is of type List<Message>, the following should work:
var model = new ViewModel();
int UserID = int.Parse(User.Identity.GetID());
model.Messages = db.Message.Where(m => m.ReceiverID == UserID || m.SenderID == UserID).ToList();
Make Messages type IEnumerable

Error with mapping entities in EF

I am trying to implement Asp.net Identity 2.0 with DB first.
I have imported my model.edmx into the project. It contains all the tables I need with the correct information and structure.
In the database there is a table called 'FSKUsers' I have edited this to contain the needed fields of the AspNetUsers which is the default table for Identity 2.0
So in my Identity DB Context I have mapped my FskUser class (which is a high level user for Identity sake)
public class IdentityDbContext : IdentityDbContext<FskUser, FskRole, int, FskUserLogin, FskUserRole, FskUserClaim>
{
public IdentityDbContext()
: base("FSK_FskNetworksEntities")
{
}
protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
var userEntity = modelBuilder.Entity<FskUser>();
userEntity.ToTable("FSKUsers", "dbo");
userEntity.Property(p => p.Id).HasColumnName("FSKUserId");
userEntity.Property(p => p.PasswordHash).HasColumnName("Password");
}
public static IdentityDbContext Create()
{
return new IdentityDbContext();
}
}
So basically I want to map the class FskUser to the Data Base table called FSKUser which is also contained in my .edmx model.
When I run the website I get the following error.
The entity type FskUser is not part of the model for the current context
My two POCO classes:
The one from my edmx model:
public partial class FSKUser
{
public FSKUser()
{
this.AspNetUserClaims = new HashSet<AspNetUserClaim>();
this.AspNetUserLogins = new HashSet<AspNetUserLogin>();
this.FSKDevices = new HashSet<FSKDevice>();
this.FSKEventLogs = new HashSet<FSKEventLog>();
this.FSKReports = new HashSet<FSKReport>();
this.FSKTransactions = new HashSet<FSKTransaction>();
this.FSKTriggers = new HashSet<FSKTrigger>();
this.UdlDownloads = new HashSet<UdlDownload>();
this.AspNetRoles = new HashSet<AspNetRole>();
this.FSKCompanies = new HashSet<FSKCompany>();
}
public int FSKUserId { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
public bool EmailConfirmed { get; set; }
public string PhoneNumber { get; set; }
public bool PhoneNumberConfirmed { get; set; }
public string Password { get; set; }
public string SecurityStamp { get; set; }
public bool TwoFactorEnabled { get; set; }
public Nullable<System.DateTime> LockoutEndDateUtc { get; set; }
public bool LockoutEnabled { get; set; }
public int AccessFailedCount { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public byte FSKAccessLevelId { get; set; }
public string AddressStreet1 { get; set; }
public string AddressStreet2 { get; set; }
public string AddressStreet3 { get; set; }
public string AddressPostCode { get; set; }
public Nullable<int> CreatorId { get; set; }
public Nullable<System.DateTime> CreateDate { get; set; }
public string ConfirmationToken { get; set; }
public Nullable<bool> IsConfirmed { get; set; }
public Nullable<System.DateTime> LastPasswordFailureDate { get; set; }
public Nullable<int> PasswordFailuresSinceLastSuccess { get; set; }
public Nullable<System.DateTime> PasswordChangedDate { get; set; }
public string PasswordVerificationToken { get; set; }
public string PasswordVerificationTokenExpirationDate { get; set; }
public bool IsDeleted { get; set; }
public Nullable<int> CostCentreId { get; set; }
public Nullable<int> AdminPasswordResetUserId { get; set; }
public Nullable<System.DateTime> PreviousLogInDate { get; set; }
public System.Guid msrepl_tran_version { get; set; }
public virtual ICollection<AspNetUserClaim> AspNetUserClaims { get; set; }
public virtual ICollection<AspNetUserLogin> AspNetUserLogins { get; set; }
public virtual ICollection<FSKDevice> FSKDevices { get; set; }
public virtual ICollection<FSKEventLog> FSKEventLogs { get; set; }
public virtual ICollection<FSKReport> FSKReports { get; set; }
public virtual ICollection<FSKTransaction> FSKTransactions { get; set; }
public virtual ICollection<FSKTrigger> FSKTriggers { get; set; }
public virtual ICollection<UdlDownload> UdlDownloads { get; set; }
public virtual ICollection<AspNetRole> AspNetRoles { get; set; }
public virtual ICollection<FSKCompany> FSKCompanies { get; set; }
}
The one I use in my Identity Config
public class FskUser : IdentityUser<int, FskUserLogin, FskUserRole, FskUserClaim>
{
[Display(Name = "First Name")]
[Required(ErrorMessage = "First Name is Required.")]
public string FirstName { get; set; }
[Display(Name = "Last Name")]
[Required(ErrorMessage = "Last Name is Required.")]
public string LastName { get; set; }
[MaxLength(20)]
[Display(Name = "Cell Number")]
[RegularExpression(#"^\(?([0-9]{3})\)?[-. ]?([0-9]{3})[-. ]?([0-9]{4})$", ErrorMessage = "Entered phone format is not valid.")]
[StringLength(10, ErrorMessage = "The {0} must be 10 numbers long.", MinimumLength = 10)]
public override string PhoneNumber { get; set; }
[Display(Name = "Access Level")]
public byte? FSKAccessLevelId { get; set; }
[Display(Name = "Street Address 1")]
public string AddressStreet1 { get; set; }
[Display(Name = "Street Address 2")]
public string AddressStreet2 { get; set; }
[Display(Name = "Street Address 3")]
public string AddressStreet3 { get; set; }
[Display(Name = "Postal Code")]
public string AddressPostCode { get; set; }
[Display(Name = "Previous Login")]
public Nullable<DateTime> PreviousLogInDate { get; set; }
[Display(Name = "Account Confirmed")]
public Nullable<bool> IsConfirmed { get; set; }
[Display(Name = "Last Password Failier")]
public Nullable<DateTime> LastPasswordFailureDate { get; set; }
[Display(Name = "Password Last Changed")]
public Nullable<DateTime> PasswordChangedDate { get; set; }
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<FskUser, int> manager)
{
//TODO: add option for web and api (to create different auth types
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
return userIdentity;
}
}
When you use Database first approach with edmx file OnModelCreating method is never called. You may check that with debugger.

CodeFirst copies properties

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?

Categories