Update an entity in database - c#

I have these two entities:
public class TblUser
{
public long Userid { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public string PasswordSalt { get; set; }
public string FullName { get; set; }
public virtual ICollection<TblNotify> TblNotifies { get; set; }
}
public partial class TblNotify
{
public Guid NotifyId { get; set; }
public string Message { get; set; }
public virtual TblUser ApprovalUser { get; set; }
}
The table tblNotify has a foreign key Userid.
DbContext was initially built as singleton service.
I call an update method:
uow.GetRepository<tblNotify>().Update(item);
It almost always updates successfully, but rarely, I got this error:
The instance of entity type 'Tbluser' cannot be tracked because another instance with the same key value for {'Userid'} is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the conflicting key values.
It's weird because I only update the tblNotify table. How could I investigate this error further?
Any help will be appreciated.

Related

EF Core introducing foreign key constraint on table may cause cycles or multiple cascade paths

I have a User entity:
public class User
{
[Key]
public string Username { get; set; }
}
and a Message entity:
public class Message
{
public int Id { get; set; }
public string Text { get; set; }
public DateTime Date { get; set; }
public User Sender { get; set; }
public User? Recipient { get; set; }
}
and my context is configured like this:
public class DummyContext: DbContext
{
public DummyContext(DbContextOptions<DummyContext> options)
: base(options){ }
public DbSet<Message> Messages { get; set; } = null!;
public DbSet<User> Users { get; set; } = null!;
}
Everything works fine and i can add-migration and update-database
Then i try to add another Invoice entity:
public class Invoice
{
public int Id { get; set; }
public User Sender { get; set; }
public User Recipient { get; set; }
public string? Description { get; set; }
public DateTime Date{ get; set; }
public float Amount { get; set; }
}
and add the DbSet to the context
...
public DbSet<Invoice> Invoices{ get; set; } = null!;
...
This time i add-migration and update-database but it gives me an error:
The introduction of the FOREIGN KEY constraint 'FK_Invoices_Users_SenderUsername' in the 'Invoices' table can result in the creation of loops or more propagation paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION or change the other FOREIGN KEY constraints.
And i cant quite figure out why it wasnt giving me the same error for the messages,
I want the message to delete on cascade if the user is deleted and that works fine but as soon as i try to do the same thing with the invoices it gives me this error.
I dont want to add OnDelete No action since i want the invoices to get deleted on user deletion too.

Optimistic Concurrency Exception During Synchronous Update Call

I am attempting to modify a single boolean property on my Invoice entity.
This is my class:
public class Invoice : SoftDeletableEntity, IIsActive
{
public Invoice()
{
IsEditable = true;
}
[ForeignKey("Booking")]
public int BookingId { get; set; }
public Booking Booking { get; set; }
[ForeignKey("Customer")]
public int CustomerId { get; set; }
public Customer Customer { get; set; }
public string OurReference { get; set; }
public string CustomerReference { get; set; }
public DateTime InvoiceDate { get; set; }
public string InvoiceNumber { get; set; }
[ForeignKey("AccountInformation")]
public int AccountInformationId { get; set; }
public AccountInformation AccountInformation { get; set; }
public string Summary { get; set; }
public List<InvoiceInformation> ImportantInformation { get; set; }
[ForeignKey("InvoiceItem")]
public List<int> InvoiceItemIds { get; set; }
public List<InvoiceLineItem> InvoiceLineItems { get; set; }
[ForeignKey("InvoiceDocument")]
public List<int> InvoiceDocumentIds { get; set; }
public List<InvoiceDocument> InvoiceDocuments { get; set; }
public string CreatedBy { get; set; }
public string Terms { get; set; }
public bool IsReversal { get; set; }
public bool IsEditable { get; set; }
public int? ParentInvoiceId { get; set; }
}
These classes are exported as a formatted PDF. That process works quite well, and then I have this code that checks whether or not the PDF was constructed correctly, then if the export succeeds, the code sets the invoice as ineditable like so:
var doc = pdf.CreateInvoicePdf(resultModel, user);
var bytes = GetPdfBytes(doc);
if (bytes != null)
{
result.IsEditable = false;
}
unitOfWork.Commit();
When I call this "unitOfWork.Commit();" I get the following exception:
System.Data.Entity.Infrastructure.DbUpdateException: 'An error occurred while saving entities that do not expose foreign key properties for their relationships.
The inner exception:
Message "Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=472540 for information on understanding and handling optimistic concurrency exceptions."
The most recently added foreign key reference was for CustomerId, but it is set up just like all of the other foreign keys. I have checked the database for FK = 0 for all foreign key entities and there are no missing references. Also this is running on my local, so I am certain the entity was not modified by sources other than my browser.
Any help is greatly appreciated.
Here are some possible reasons which might cause such problem:
You trying to update entity with primary key Id == 0 or another default value (Guid.Empty or string.Empty). So, verify that Id is set properly.
When you try to create a new object and tell EF that it's modified using the EntityState.Modified. Then it will throw this error as it doesn't yet exist in the database. So, try to use EntityState.Added.
You tried to update or delete a row but the row doesn't exist.

SQL Server foreign key window issue for newly created EF Code first table

I don't know if anyone face this issue or it's just something else.
I am using a EF code-first architecture.
Here is my first class :
public class PerformanceSurchargeGeneralSettings : FullAuditedEntity
{
public int PerformanceID { get; set; }
public Performance Performance { get; set; }
public int SurchargeId { get; set; }
public Surcharges Surcharge { get; set; }
}
And here is the second class:
public class Surcharges : FullAuditedEntity
{
public string Name { get; set; }
public ICollection<PerformanceSurchargeGeneralSettings> PerformanceSurchargeGeneralSettings{ get; set; }
}
Everything works fine, I can add migration, update my database but if I go to table and check for foreign key reference, I can't see primary key table. See this screenshot here:
I am not able to find newly added table that is Surcharge in the dropdown of primary key table.
And if I execute SP_help for this table, I can find all foreign keys, see the screenshot:
I don't understand where exactly the issue is ...
H,
Change your classes as below;
[Table("PerformanceSurchargeGeneralSettings")]
public class PerformanceSurchargeGeneralSetting : FullAuditedEntity
{
[ForeignKey("PerformanceId")]
public virtual Performance Performance { get; set; }
public int PerformanceId { get; set; }
[ForeignKey("SurchargeId")]
public virtual Surcharge Surcharge { get; set; }
public int SurchargeId { get; set; }
}
[Table("Surcharges")]
public class Surcharge : FullAuditedEntity
{
[MaxLength(128)]
public string Name { get; set; }
public virtual ICollection<PerformanceSurchargeGeneralSetting> PerformanceSurchargeGeneralSettings{ get; set; }
}
My advises
Use singular names for classes. Surcharges => Surcharge.
Give MaxLength to string properties.
Use the same case for all Id fields. PerformanceID => PerformanceId. (like you did for SurchageId).
Add virtual key when you want to load data with lazy loading.

Entity framework creating a non existent column in the query

This has been puzzling me for quite some time but I keep getting an invalid identifier error when my entity framework tries to execute an oracle query. The classes in question are the following:
public class Projectship : ModelTrackingBase
{
[Column("PROJECTID")]
public long ProjectId { get; set; }
[Column("VISITID")]
public long VisitId { get; set; }
public virtual Bpid Bpid { get; set; } //new
public virtual Visit Visit { get; set; }
}
and
public class Bpid : EntityIdBase
{
[Column("BUDPRJID")]
[MaxLength(38)]
public string BPId { get; set; }
[Column("DESCRIPTION")]
[MaxLength(255)]
public string Description { get; set; }
[Column("CSTOBJ")]
[MaxLength(255)]
public string Custobj { get; set; }
[Column("PVID")]
[MaxLength(255)]
public string Pvid { get; set; }
public virtual ICollection<Projectship> Projectships { get; set; }
public IEnumerable<Visit> Visits
{
get { return Projectships.Select(p => p.Visit); }
}
[NotMapped]
public string DisplayName
{
get { return string.Format("{0}: {1}", BPId , Description); }
}
}
Now the EntityIdBase has the following:
public class EntityIdBase : EntityBase
{
[Column("ID")]
public long Id { get; set; }
}
It tries to keep on looking for a column Bpid_Id in the query. Does someone have any idea?
Bpid_id is created by EF because it can't automatically determine the relationship. Try adding the annotation:
[ForeignKey("ID")]
public virtual Bpid Bpid { get; set; } //new
You have specified a navigation property in the Projectship class
public virtual Bpid Bpid { get; set; }
You have not specified a foreign key to go with the navigation property so Entity Framework has chosen one, and it has chosen the name Bpid_Id. And it should be in the database. It should not be "non-existent".
You will probably find it easier to use Entity Framework if you add a foreign key like this:
public int BpidId { get; set; }
References:
Why does Entity Framework Reinsert Existing Objects into My Database?
Making Do with Absent Foreign Keys

Unable to determine the principal end of an association - Entity Framework Model First

I have created Entity Data Model in Visual Studio. Now I have file with SQL queries and C# classes generated from Model.
Question:
Classes are generated without annotations or code behind (Fluent API). Is it OK? I tried to run my application but exception was thrown:
Unable to determine the principal end of an association between the types 'Runnection.Models.Address' and 'Runnection.Models.User'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.
I read that I can not use Fluent API with "Model First". So what can I do?
Code:
User
public partial class User
{
public User()
{
this.Events = new HashSet<Event>();
this.CreatedEvents = new HashSet<Event>();
}
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Photo { get; set; }
public int EventId { get; set; }
public string Nickname { get; set; }
public OwnerType OwnerType { get; set; }
public NetworkPlaceType PlaceType { get; set; }
public virtual ICollection<Event> Events { get; set; }
public virtual Address Address { get; set; }
public virtual ICollection<Event> CreatedEvents { get; set; }
public virtual Owner Owner { get; set; }
}
Address
public partial class Address
{
public int Id { get; set; }
public string Street { get; set; }
public string StreetNumber { get; set; }
public string City { get; set; }
public string ZipCode { get; set; }
public string Country { get; set; }
public virtual User User { get; set; }
}
Context
//Model First does not use this method
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Address>().HasRequired(address => address.User)
.WithRequiredDependent();
modelBuilder.Entity<User>().HasRequired(user => user.Address)
.WithRequiredPrincipal();
base.OnModelCreating(modelBuilder);
}
You have to specify the principal in a one-to-one relationship.
public partial class Address
{
[Key, ForeignKey("User")]
public int Id { get; set; }
public string Street { get; set; }
public string StreetNumber { get; set; }
public string City { get; set; }
public string ZipCode { get; set; }
public string Country { get; set; }
public virtual User User { get; set; }
}
By specifying a FK constraint, EF knows the User must exists first (the principal) and the Address follows.
Further reading at MSDN.
Also, see this SO answer.
Updated from comments
In the designer, select the association (line between Users & Address). On the properties window, hit the button with the [...] on Referential Constraint (or double click the line). Set the Principal as User.
Error:
Had same error of "Unable to determine the principal end of an association between the types 'Providence.Common.Data.Batch' and 'Providence.Common.Data.Batch'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.".
HOWEVER, note that this is the SAME table.
Cause: My database was MS SQL Server. Unfortunately when MS SQL Server's Management Studio adds foreign keys, it adds the default foreign key as Batch ID column of Batch table linking back to itself. You as developer are suppose to pick another table and id to truly foreign key to, but if you fail to it will still allow entry of the self referencing FK.
Solution:
Solution was to delete the default FK.
Cause 2: Another situation is that the current table may be fixed but the old historical image of the table when the EF's edmx was done had the default FK.
Solution 2: is to delete the table from the Model Browser's Entity Types list and click "yes" and then "Update Model from the Database" again.

Categories

Resources