I have the following Models:
public interface Item
{
public int Id { get; set; }
}
public class ComponentOwner : Item
{
public int Id { get; set; }
public Component Component { get; set; }
public AppUser? User { get; set; }
public DateTime ModifiedDate { get; set; }
public AppUser? UpdatedBy { get; set; }
}
public class AppUser : IdentityUser
{
public string FirstName { get; set; } = "";
public string LastName { get; set; } = "";
}
and the following async Task that saves the item to the database:
private async Task<Item> SaveItem(Item item)
{
Item updatedItem = null;
using var context = _dbContextFactory.CreateDbContext();
try
{
if (item.Id == 0)
{
context.Add(item);
await context.SaveChangesAsync();
}
When I Save a new ComponentOwner, context.Add(Item) adds the item, but also tries to add a new 'AppUser' at the same time. This causes issues because the AppUser is already created.
Is there a way that I can specify to add the ComponentOwner but not the AppUser?
as soon as 'Context.Add(item)' is hit, it wants to add an AppUser as well as the Component. I only want it to add the ComponentOwner however..
EF Core relies on tracking to determine what to do with entities. In this case it seems that item.User is not tracked, so EF tries to add it. There are multiple possible solution to this. To name a few:
If you are sure that user exists, you can just attach the entity:
if(item.User is not null)
context.Users.Attach(item.User); // or just context.Attach(item.User);
Fetch user from database and assign it to the root entity:
if (item.User is not null)
{
var user = context.Users.FirstOrDefault(u => u.Id == item.User.Id); // TODO: handle null
item.User = user;
}
Use Find:
Finds an entity with the given primary key values. If an entity with the given primary key values is being tracked by the context, then it is returned immediately without making a request to the database. Otherwise, a query is made to the database for an entity with the given primary key values and this entity, if found, is attached to the context and returned. If no entity is found, then null is returned.
if (item.User is not null)
{
var user = context.Users.Find(item.User.Id); // TODO: handle null
item.User = user;
}
I have a table called Quotations and it has an unique string field called QuotationNo.
public class Quotation
{
[Key]
public int Id { get; set; } //PK
public string QuotationNo{ get; set; } // Pattern QUOT/12-22/00001 => QUOT + MONTH-YEAR + PrimaryKey.ToStrin("5d");
}
So I have implemented it by calling _db.SaveChanges() method twice as follows.
if (ModelState.IsValid)
{
_db.Quotations.Add(quot);
_db.SaveChanges(); // 1 time saving
quot.QuotationNo= "QUOT/" + DateTime.Today.ToString("dd-MM/") + quot.Id.ToString("D5");
_db.Quotations.Update(quot);
_db.SaveChanges(); // 2 time saving
}
Is there a short way to do this?
I found this method is more clear.
Step 1: Creating new field in the table to store DateCreated.
Step 2: Making QuotationNo a virtual and NotMapped field, which is always a calculated/generated field.
See the code
public class Quotation
{
[Key]
public int Id { get; set; } //PK
[Required]
public DateTime DateCreated { get; set; } //New field to store quotation created date.
[NotMapped]
public virtual string? QuotationNo //Ax Key(Quotation No: QUOT/01-22/0000001=> PQTN/mmYY/0000000)
{
get
{
return $"QUOT/{this.DateCreated:dd-MM/}{PolyCostingId:D5}";
}
set
{
this.PolyCostingCode = value;
}
}
}
Please try this
public class Quotation
{
public int Id { get; set; } //PK
public string QuotationNo
{
get
{
return string.IsNullOrWhiteSpace(this.QuotationNo)
? $"QUOT/{DateTime.Today:dd-MM:hh:mm:ss/}{Id:D7}"
: this.QuotationNo;
}
set { this.QuotationNo = value; }
}}
For example
var x = new Quotation();
x.Id = 12345;
var quotationNo = x.QuotationNo;
// quotationNo will be QUOT/22-12/0012345
Some reference here Setting the default value of a DateTime Property to DateTime.Now inside the System.ComponentModel Default Value Attrbute
I keep getting this error when I try to submit to the database:
A dependent property in a ReferentialConstraint is mapped to a store-generated column. Column: 'NPPRProvId'
Here's where it breaks:
public static bool Save(NPPR_Provider provider, State state, string filename, bool validateBeforeSave = true )
{
using (var db = new NPPRContext(state))
{
var prov = new NPPR_Provider()
{
First = provider.First,
Middle = provider.Middle,
Last = provider.Last,
DateOfBirth = provider.DateOfBirth,
DateOfDeath = provider.DateOfDeath,
Gender = provider.Gender,
SSN = provider.SSN,
DegreeCode = provider.DegreeCode,
BusinessName = provider.BusinessName,
DbaName = provider.DbaName,
Action = "A",
EffectiveDate = "20121212",
EndDate = "99991231",
NPPR_ServLocation = new NPPR_ServLocation()
{
EnrollmentType = provider.NPPR_ServLocation.EnrollmentType,
OrganizationType = provider.NPPR_ServLocation.OrganizationType,
ProviderTypeCode = provider.NPPR_ServLocation.ProviderTypeCode,
IRSTaxAssociations = provider.NPPR_ServLocation.IRSTaxAssociations,
NPIAssociations = provider.NPPR_ServLocation.NPIAssociations,
Address = provider.NPPR_ServLocation.Address
},
NPPR_Header = new NPPR_Header()
{
FileName = filename,
TransactionDate = Utilities.DateTimeToPRNDate(DateTime.Now),
FileLoadDate = DateTime.Now,
SubmitterId = "M00000503",
Purpose = "A",
Action = "A"
}
};
foreach(var npi in prov.NPPR_ServLocation.NPIAssociations)
{
npi.NPIType = prov.NPPR_ServLocation.OrganizationType == "I" ? "1" : "2";
}
prov.NPPR_ServLocation.Licenses = SegmentOrNull<NPPR_Licenses>(provider.NPPR_ServLocation, "Licenses", "LicenseNumber");
prov.NPPR_ServLocation.Certifications = SegmentOrNull<NPPR_Certifications>(provider.NPPR_ServLocation, "Certifications", "CertificationNumber");
prov.NPPR_ServLocation.Specialties = SegmentOrNull<NPPR_Specialties>(provider.NPPR_ServLocation, "Specialties", "SpecialtyCode");
prov.NPPR_ServLocation.Taxonomies = SegmentOrNull<NPPR_Taxonomies>(provider.NPPR_ServLocation, "Taxonomies", "TaxonomyCode");
prov.NPPR_ServLocation.OtherIds = SegmentOrNull<NPPR_OtherIds>(provider.NPPR_ServLocation, "OtherIds", "IdentifierTypeId");
prov.NPPR_ServLocation.GroupAssociations = SegmentOrNull<NPPR_GroupAssociations>(provider.NPPR_ServLocation, "GroupAssociations", "ProviderLocationId");
db.NPPR_Provider.Add(prov);
if (validateBeforeSave)
db.SaveChangesWithValidation();
else
db.SaveChanges();
return true;
}
}
db.SaveChanges() is where, according to the stacktrace, the exception is thrown. This function was originally written for EF Core, but due to issues with the server, I was forced to turn everything to EF6.4. Under Core, this method worked fine, but under EF6, it throws an exception. I've tried a few things I've read on other SO questions but so far no luck.
Specifically the exception throws on the NPPR_Provider primary key, NPPRProvId, which at no point in my code is ever read or written, except to be defined in the model.
In SQL, the NPPRProvId is PK, int, not null
The model involved:
public class NPPR_Provider : Provider
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int NPPRProvId { get; set; }
//[ForeignKey("NPPR_Header")]
public int? NPPRFileId { get; set; }
[ForeignKey("NPPRFileId")]
public NPPR_Header NPPR_Header { get; set; }
[ForeignKey("NPPRProvId")]
public NPPR_ServLocation NPPR_ServLocation { get; set; }
}
What am I doing wrong here and how might I fix it? I'm still fairly new to EF and this is my first major project in EF and MVC, and in the .NET framework in general.
In EF Core the NPPR_ServLocation could be an owned object but to my knowledge in EF 6 there are not owned objects; you need to define them explicitly in a separate table and give them keys.
public class NPPR_Provider : Provider
{
public int NPPR_ProviderId { get; set; }
public NPPR_Header NPPR_Header { get; set; }
public NPPR_ServLocation NPPR_ServLocation { get; set; }
… // data properties here
}
public class NPPR_Header {
public int NPPR_HeaderId {get;set;}
public int NPPR_ProviderId {get;set;}
public NPPR_Provider {get;set;}
… // data properties here
}
public class NPPR_ServLocation {
public int NPPR_ServLocationId {get;set;}
public int NPPR_ProviderId {get;set;}
public NPPR_Provider {get;set;}
… // data properties here.
}
public class Person
{
[Required]
public int? KupaId { get; set; }
[ForeignKey("KupaId")]
public Kupa Kupa { get; set; }
public int? newKupaId { get; set; }
[ForeignKey("newKupaId")]
public Kupa NewKupa { get; set; }
}
public class Kupa
{
public int Id { get; set; }
[Index("Ix_uniqueId", IsUnique = true)]
public int ? uniqueId { get; set; }
}
public class MyController:Controller
{
public Json EditKupa(Expression<Func<Person,bool>> criteria )
{
using (IKupotRepository<Person> _IPersonRepository = new SQlRepository<Person>())
{
Person personToEdit=_IPersonRepository.SingleOrDefault(criteria,GetIncludeProperties());
> //Getting the new kupa obj from db
newKupa = GetKupa(UniqueId);
<//changing the unique property to null
personToEdit.Kupa.ToremId = null;
personToEdit.Kupa.State = State.Modified;
personToEdit.NewKupa = newKupa;
>//Assign the unique id property the value that was in the first Kupa
personToEdit.NewKupa.ToremId = 1;
personToEdit.newKupaId = newKupa.Id;
personToEdit.NewKupa.State = State.Modified;
_IPersonRepository.SaveChanges();
}
}
when calling saveChanges() getting an exception :unique key violation , when looking at the sql profiler i can see that EF 6 generates an update query for both the Kupa object but it tries to update the NewKupa.uniqueId before updating the Kupa.uniqueId ?
Assuming you are using SQL Server as a database server this is happening because you allow NULL values in that column and NULL = NULL is NULL so if you have multiple rows with NULL on that column you'll get the error.
To implement this in SQL statements will be like this:
CREATE UNIQUE NONCLUSTERED INDEX Idx_UniqueId_NotNull
ON Kupa(uniqueId)
WHERE uniqueId IS NOT NULL;
However, to do this in EF there is no easy way, but there is a workaround in this SO answer here.
I have primary table and 3 foreign key tables and trying to save all at once. Some time some OK and some time giving error.
public partial class meeting_abstract
{
public int meeting_abstract_id { get; set; }
public int meeting_id { get; set; }
public System.DateTime submission_date { get; set; }
public virtual ICollection<abstract_author> abstract_author { get; set; }
public virtual ICollection<abstract_category> abstract_category { get; set; }
public virtual ICollection<abstract_questions> abstract_questions { get; set; }
}
var meeting_abstract = new meeting_abstract();
meeting_abstract.meeting_id = meetingAbstract.Meeting.meeting_id;
meeting_abstract.submission_date = DateTime.Now;
meeting_abstract.abstract_questions = new Collection<abstract_questions>();
var abstractQuestion = new abstract_questions();
abstractQuestion.meeting_question_id = Convert.ToInt32(meetingAbstract.AbstractTitleInEnglishId);
abstractQuestion.abstract_question_answer = meetingAbstract.AbstractTitleInEnglishText;
meeting_abstract.abstract_questions.Add(abstractQuestion);
abstractQuestion = new abstract_questions();
abstractQuestion.meeting_question_id = Convert.ToInt32(meetingAbstract.AbstractTitleInLanguageId);
abstractQuestion.abstract_question_answer = meetingAbstract.AbstractTitleInLanguageText;
meeting_abstract.abstract_questions.Add(abstractQuestion);
meeting_abstract.abstract_author.Add(meetingAbstract.primaryAuthor);
var abstractCategory = new abstract_category()
{
meeting_category_id = meetingCategory.meeting_category_id
};
meeting_abstract.abstract_category = new Collection<abstract_category>();
meeting_abstract.abstract_category.Add(abstractCategory);
_abstractRewriteEntities.meeting_abstract.Add(meeting_abstract);
_abstractRewriteEntities.SaveChanges();
Whats wrong here? I cannot save all together?
When adding more than one item, with a property defined as the identity, you will need to give those entities a unique key even though it will ultimately be set by the db. We do this in our project by defining a partial class for that entity, and in OnCreated making sure they have a unique value for their identity.
For example:
public partial class abstract_questions
{
private static int _newIdentity = 0;
partial void OnCreated()
{
//Set an identity value so when two new entities
// are created Entity Framework doesn't whinge
// on the server because of duplicate keys
_newIdentity = _newIdentity - 1;
// Set whatever is defined as the identity/pk property
this.Id = _newIdentity;
}