How to insert values into a table with optional relationship in ef? - entity-framework-core

I have those two entities, PatientRegistry and PatientAccount. The relationship between them is 1-0..1. I am trying to seed in my primary table PatientRegistry but I keep getting null errors for required fields in my optional table PatientAccount, How can I insert values in my primary table without the need to seed in my optional table as well?
Unhandled Exception: Microsoft.EntityFrameworkCore.DbUpdateException:
An error occurred while updating the entries. See the inner exception
for details. ---> System.Data.SqlClient.SqlException: Cannot insert
the value NULL into column 'Password', table
'ArtCoreDb.dbo.AspPatientsAccount'; column does not allow nulls.
UPDATE fails.
public class PatientRegistry {
[DatabaseGenerated (DatabaseGeneratedOption.Identity)]
[Display (Name = "Record Id")]
public long RecordId { get; set; }
[Key, DatabaseGenerated (DatabaseGeneratedOption.None)]
[Display (Name = "Patient File Number")]
public long PatientFileId { get; set; }
[Required, StringLength (50)]
[Display (Name = "First Name")]
public string FirstName { get; set; }
public virtual ICollection<PartnerRegistry> Partners { get; set; }
public virtual PatientAccount PatientAccount { get; set; }
}
public class PatientAccount {
[Key, DatabaseGenerated (DatabaseGeneratedOption.Identity)]
public long RecordId { get; set; }
[Required]
public string Password { get; set; }
[Required, StringLength (15)]
public string MobileNo { get; set; }
public bool IsConfirmedPhoneNumber { get; set; } = false;
public bool IsConfirmedEmailAddress { get; set; } = false;
public bool IsLocked { get; set; } = false;
public int? FailedAttempts { get; set; }
public DateTimeOffset? LastLoggedIn { get; set; }
public DateTimeOffset DateCreated { get; set; }
[Timestamp]
public byte[] RowVersion { get; set; }
public long? PatientFileId { get; set; }
public virtual PatientRegistry PatientFile { get; set; }
}
And my fluent API,
protected override void OnModelCreating (ModelBuilder builder) {
base.OnModelCreating (builder);
builder.Entity<PatientRegistry> ()
.HasOne (a => a.PatientAccount)
.WithOne (b => b.PatientFile)
.HasForeignKey<PatientAccount> (c => c.PatientFileId)
.OnDelete (DeleteBehavior.Cascade);
}
And I seed,
if (!context.PatientsRegistry.Any ()) {
context.PatientsRegistry.AddRange (
new PatientRegistry {
PatientFileId = 1111,
FirstName = "John"
}
);
context.SaveChanges ();
}
works only if I add ,,
PatientAccount =
new PatientAccount {
PatientFileId = 1111,
CountryCodeId = context.Countries.Where (g => g.Name == "United States of America").SingleOrDefault ().Id,
AreaCode = 424,
Email = "aamaizar#gmail.com",
MobileNo = "3244990",
IsConfirmedEmailAddress = false,
IsConfirmedPhoneNumber = false,
IsLocked = false,
Password = "213123",
},
in reality, I want to be able to insert in PatientsRegistry table without the need to insert into PatientAccount

Using Add (or AddRange) marks all reachable entities in the graph in added state, I just have to added PatientAccount prop to my object during seeding
new PatientRegistry { PatientFileId = 1111, FirstName = "John", PatientAccount = {.......} }
Ref

Related

EF Core 6: Reading two tables using navigations doesn't load child table data

The role property of a relation record doesn't get read/initialized (i.e. the data from the included table doesn't get read). Why is that? The data is in the database.
public class IDM_Role
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
public long role_id { get; set; } = -1;
[StringLength(80)]
public string role_name { get; set; } = string.Empty;
}
public class IDM_Relation
{
[Required]
[StringLength(80)]
public string account_id { get; set; } = string.Empty;
[Required]
[ForeignKey("IDM_Role")]
public long role_id { get; set; } = 0;
[ForeignKey("role_id")]
public virtual IDM_Role role { get; set; }
}
modelBuilder.Entity<IDM_Relation>()
.HasKey(e => new { e.role_id, e.account_id })
.HasName("PK_IDM_Relation");
[EnableQuery(PageSize = 15)]
public IQueryable<IDM_Relation> Get()
{
return _context.idm_relations.Include(e => e.role);
}
Removing "virtual" from the property IDM_Role role doesn't help.

Entity Framwork Update many to many

I am new to ef core. I am trying to implement many to many .
Here is my DBContext
public class MaxCiSDbContext : DbContext
{
public DbSet<Job> Jobs { get; set; }
public DbSet<Staff> Staffs { get; set; }
public MaxCiSDbContext(DbContextOptions<MaxCiSDbContext> options) : base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Job>()
.HasMany(t => t.Staffs)
.WithMany(t => t.Jobs);
base.OnModelCreating(modelBuilder);
}
}
and Here is my Staff Class
public class Staff
{
public string Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
public string Mobile { get; set; }
public string Address { get; set; }
//Navigation
public virtual ICollection<Job> Jobs { get; set; }
}
Here is my Job Class
public class Job
{
[Key]
public string Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string State { get; set; }
public string ClientOrderNumber { get; set; }
public string StartDate { get; set; }
public string DueDate { get; set; }
public string CompletedDate { get; set; }
public string ClientId { get; set; }
public string ManagerId { get; set; }
public string PartnerId { get; set; }
//Navigation
public virtual ICollection <Staff> Staffs { get; set; }
}
I Call an API which returns a XmlDocument, I read that document and update database.
Here is how I deal with xmldocument.
//Fetch Current Jobs and populate to DB
XmlDocument apiresults = JobMethods.GetCurrent();
XmlNodeList nodes = apiresults.DocumentElement.SelectNodes("/Response/Jobs/Job");
foreach (XmlNode node in nodes)
{
Job MaxCiSJob = new Job()
{
Id = node.SelectSingleNode("ID").InnerText,
Name = node.SelectSingleNode("Name").InnerText,
Description = node.SelectSingleNode("Description").InnerText,
State = node.SelectSingleNode("State").InnerText,
ClientOrderNumber = node.SelectSingleNode("ClientOrderNumber").InnerText,
StartDate = node.SelectSingleNode("StartDate").InnerText,
DueDate = node.SelectSingleNode("DueDate") != null ? node.SelectSingleNode("DueDate").InnerText : "",
CompletedDate = node.SelectSingleNode("CompletedDate") != null ? node.SelectSingleNode("CompletedDate").InnerText : "",
ClientId = node.SelectSingleNode("Client/ID").InnerText,
ManagerId = node.SelectSingleNode("Manager/ID") != null ? node.SelectSingleNode("Manager/ID").InnerText : "",
PartnerId = node.SelectSingleNode("Partner") != null ? node.SelectSingleNode("Partner").InnerText : ""
};
XmlNodeList Assigned = node.SelectNodes("Assigned/Staff");
MaxCiSJob.Staffs = new Collection<Staff>();
foreach (XmlNode staffNode in Assigned)
{
var staffId = staffNode.SelectSingleNode("ID").InnerText;
var staff = _db.Staffs.Find(staffId);
if(staff != null)
{
MaxCiSJob.Staffs.Add(staff);
}
}
if (_db.Jobs.Find(MaxCiSJob.Id) == null)
{
//Insert Record
_db.Jobs.Add(MaxCiSJob);
}
else
{
// UPDATE recorde
_db.Jobs.Update(MaxCiSJob);
}
}
_db.SaveChanges();
}
Everything works well when I run the program for the first time(The linking table ,"JobStaff", is empty) but when I run the Program for the second time I get an excetpion:
SqlException: Violation of PRIMARY KEY constraint 'PK_JobStaff'. Cannot insert duplicate key in object 'dbo.JobStaff'. The duplicate key value is (J14995, 557898).
Can someone please help me on how can I resolve this issue.
Running your code EF core wants to add entities anyway. Because your entities are not attached.
Try this code:
//Fetch Current Jobs and populate to DB
XmlDocument apiresults = JobMethods.GetCurrent();
XmlNodeList nodes = apiresults.DocumentElement.SelectNodes("/Response/Jobs/Job");
foreach (XmlNode node in nodes)
{
var id = node.SelectSingleNode("ID").InnerText;
Job MaxCiSJob = _db.Jobs.Find(id);
if (MaxCiSJob == null)
{
MaxCiSJob = new Job() { Id = id };
_db.Jobs.Add(MaxCiSJob);
}
MaxCiSJob.Name = node.SelectSingleNode("Name").InnerText;
MaxCiSJob.Description = node.SelectSingleNode("Description").InnerText;
MaxCiSJob.State = node.SelectSingleNode("State").InnerText;
MaxCiSJob.ClientOrderNumber = node.SelectSingleNode("ClientOrderNumber").InnerText;
MaxCiSJob.StartDate = node.SelectSingleNode("StartDate").InnerText;
MaxCiSJob.DueDate = node.SelectSingleNode("DueDate") != null ? node.SelectSingleNode("DueDate").InnerText : "";
MaxCiSJob.CompletedDate = node.SelectSingleNode("CompletedDate") != null ? node.SelectSingleNode("CompletedDate").InnerText : "";
MaxCiSJob.ClientId = node.SelectSingleNode("Client/ID").InnerText;
MaxCiSJob.ManagerId = node.SelectSingleNode("Manager/ID") != null ? node.SelectSingleNode("Manager/ID").InnerText : "";
MaxCiSJob.PartnerId = node.SelectSingleNode("Partner") != null ? node.SelectSingleNode("Partner").InnerText : "";
XmlNodeList Assigned = node.SelectNodes("Assigned/Staff");
foreach (XmlNode staffNode in Assigned)
{
MaxCiSJob.Staffs.Clear();
var staffId = staffNode.SelectSingleNode("ID").InnerText;
var staff = _db.Staffs.Find(staffId);
if (staff != null)
{
MaxCiSJob.Staffs.Add(staff);
}
}
}
_db.SaveChanges();
And you should change your domains this way in order not to get NullReferenceException:
public class Staff
{
public string Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
public string Mobile { get; set; }
public string Address { get; set; }
//Navigation
public virtual ICollection<Job> Jobs { get; set; } = new Collection<Job>();
}
public class Job
{
[Key]
public string Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string State { get; set; }
public string ClientOrderNumber { get; set; }
public string StartDate { get; set; }
public string DueDate { get; set; }
public string CompletedDate { get; set; }
public string ClientId { get; set; }
public string ManagerId { get; set; }
public string PartnerId { get; set; }
//Navigation
public virtual ICollection<Staff> Staffs { get; set; } = new Collection<Staff>();
}

The property 'Id' is part of the object's key information and cannot be modified after the second insert

I have a table with Id as primary key
The model generated by EF is this
public partial class Home_Orchard_Users_UserPartRecord
{
public int Id { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
public string NormalizedUserName { get; set; }
public string Password { get; set; }
public string PasswordFormat { get; set; }
public string HashAlgorithm { get; set; }
public string PasswordSalt { get; set; }
public string RegistrationStatus { get; set; }
public string EmailStatus { get; set; }
public string EmailChallengeToken { get; set; }
public Nullable<System.DateTime> CreatedUtc { get; set; }
public Nullable<System.DateTime> LastLoginUtc { get; set; }
public Nullable<System.DateTime> LastLogoutUtc { get; set; }
}
When I tried to insert a data from a list, the first insert was okay but the second one I got error: The property 'Id' is part of the object's key information and cannot be modified.
foreach (var ContentItem in ListContentItem)
{
ContentItemData.Data = ContentItem.Data;
ContentItemData.ContentType_id = 3;
Context.Home_Orchard_Framework_ContentItemRecord.Add(ContentItemData);
Context.SaveChanges();
int Return_Id = ContentItemData.Id;
UserData.Id = Return_Id;
UserData.UserName = ContentItem.UserName;
UserData.Email = ContentItem.Email;
UserData.NormalizedUserName = ContentItem.NormalizedUserName;
UserData.Password = "AMQ6a4CzqeyLbWqrd7EwoaTV23fopf++3FpcBlV+Gsvgja3Ye3LwFlXVHyhAcWyKaw==";
UserData.PasswordFormat = "Hashed";
UserData.HashAlgorithm = "PBKDF2";
UserData.PasswordSalt = "FaED9QsIV9HD95m8FO5OSA==";
UserData.RegistrationStatus = "Approved";
UserData.EmailStatus = "Approved";
UserData.CreatedUtc = DateTime.Today;
Context.Home_Orchard_Users_UserPartRecord.Add(UserData);
//Context.SaveChanges();
i = i + 1;
progress = ((float)i / nCount) * 100;
Console.Write("\r{0}%", progress);
Thread.Sleep(50);
}
Why I can't insert the second time? The Id is the primary key and it's not autogenerated so it has to be input manually.

N to M relationship code first does not create the foreign key on the M-table

A SchoolclassCode can have many Pupils.
A Pupil can belong to many SchoolclassCodes.
This is an N to M relation.
I thought N to M relation work in code first by default.
But I also explicitly create the N to M relation here:
modelBuilder.Entity<SchoolclassCode>().
HasMany(c => c.Pupils).
WithMany(p => p.SchoolclassCodes).
Map(
m =>
{
m.MapLeftKey("SchoolclassCodeId");
m.MapRightKey("PupilId");
m.ToTable("SchoolclassCodePupil");
});
public class SchoolclassCode
{
public SchoolclassCode()
{
Pupils = new HashSet<Pupil>();
Tests = new HashSet<Test>();
}
public int Id { get; set; }
public string SchoolclassCodeName { get; set; }
public string SubjectName { get; set; }
public int Color { get; set; }
public string ClassIdentifier { get; set; }
public ISet<Pupil> Pupils { get; set; }
public ISet<Test> Tests { get; set; }
public Schoolyear Schoolyear { get; set; }
public int SchoolyearId { get; set; }
}
public class Pupil
{
public Pupil()
{
PupilsTests = new HashSet<PupilTest>();
SchoolclassCodes = new HashSet<SchoolclassCode>();
}
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Postal { get; set; }
public string City { get; set; }
public string Street { get; set; }
public ISet<PupilTest> PupilsTests { get; set; }
public ISet<SchoolclassCode> SchoolclassCodes { get; set; }
}
On the Pupil Table no foreign key is created at all, Why this?
For a many to many relationship, there is no foreign key on either side. The foreign keys are on the join table, which you have mapped to the table SchoolclassCodePupil:
modelBuilder.Entity<SchoolclassCode>().
HasMany(c => c.Pupils).
WithMany(p => p.SchoolclassCodes).
Map(m =>
{
m.MapLeftKey("SchoolclassCodeId");
m.MapRightKey("PupilId");
m.ToTable("SchoolclassCodePupil");
});
Entity Framework uses that junction table to determine what belongs in the somePupil.SchoolclassCodes set.

Entity Framework - Code First - Multiplicity constraint violated, The role X of the relationship Y has multiplicity 1 or 0..1

Using code first (EF 6), I created a 1 parent - 2 child relationship. Property is the parent object and Property Address as a child with 1 or 0..1 relationship. PropertyImage is another child with 1 to many relationship. PropertyImage works fine but the PropertyAddress throws error if I try to eager load .
Actual Error -
Multiplicity constraint violated.
The role 'PropertyAddress_Property_Source' of the relationship 'MyAssetTracker.DataLayer.Models.PropertyAddress_Property' has multiplicity 1 or 0..1.
// Test Function
GetProperty()
{
Property property;
using (var repo = new PropertyRepository())
{
property = repo.AllIncluding(a=>a.Images, a=>a.Address).FirstOrDefault(a => a.Id == testpropertyid);
}
}
//Property Repository
public class PropertyRepository : IPropertyRepository
{
public IQueryable<Property> AllIncluding(params Expression<Func<Property, object>>[] includeProperties)
{
IQueryable<Property> query = context.Properties;
foreach (var includeProperty in includeProperties) {
query = query.Include(includeProperty);
}
return query;
}
}
//Property Entity
public class Property : DomainModelAuditBase, IDomainModelState
{
private Address _address;
private ICollection<Asset> _assets;
private ICollection<PropertyImage> _images;
public Property()
{
_address = new Address();
_assets = new List<Asset>();
_images = new List<PropertyImage>();
}
public Guid Id { get; set; }
[StringLength(100), Required]
public string Title { get; set; }
public bool IsPrimary { get; set; }
[StringLength(255)]
public string Description { get; set; }
[NotMapped]
public State State { get; set; }
public Guid AddressId { get; set; }
public Guid UserId { get; set; }
public virtual Address Address
{
get { return _address; }
set { _address = value; }
}
public virtual ICollection<Asset> Assets
{
get { return _assets; }
set { _assets = value; }
}
public virtual User User { get; set; }
public virtual ICollection<PropertyImage> Images
{
get { return _images; }
set { _images = value; }
}
}
//PropertyAddress
public class Address : DomainModelAuditBase, IDomainModelState
{
[Key,ForeignKey("Property")]
public Guid PropertyId { get; set; }
[StringLength(255),Required]
public string AddressLine1 { get; set; }
[StringLength(255)]
public string AddressLine2 { get; set; }
[StringLength(255)]
public string City { get; set; }
[StringLength(255)]
public string StateProvince { get; set; }
[StringLength(100)]
public string PostalCode { get; set; }
[StringLength(100)]
public string Country { get; set; }
[NotMapped]
public State State { get; set; }
public virtual Property Property { get; set; }
}
Remove_address = new Address(); from Property constructor.
You could read about similar problem here
Also are you sure that you need AddressId field in Property class?