As part of an assignment, I must create a web app using Entity Framework. I am following the tutorial at https://learn.microsoft.com/en-us/aspnet/mvc/overview/getting-started/getting-started-with-ef-using-mvc/creating-an-entity-framework-data-model-for-an-asp-net-mvc-application.
There are four tables: Branch, Department, Employee and Title.
After creating a method to seed the data I have run the application in debugging mode and got the following error message:
System.Data.Entity.Infrastructure.DbUpdateException: ‘An error occurred while updating the entries. See the inner exception for details.’ SqlException: The INSERT statement conflicted with the FOREIGN KEY constraint "FK_dbo.Employee_dbo.Branch_BranchId". The conflict occurred in database “HumanResourcesWebApp1”, table “dbo.Branch”,column ‘ID’. The statement has been terminated.
I have researched this message but I am not following the answers which I have found. I would be grateful for some direction. I am also adding the structure of the classes if it helps. I understand that the issue is between the primary key of the Branch table when seen as a foreign key by the Employee table but I do not know where to make changes.
Branch:
public int ID { get; set; }
public string Address { get; set; }
public int DepartmentID { get; set; }
public virtual ICollection<Employee> Employees { get; set; }
Department:
public int ID { get; set; }
public string DepartmentName { get; set; }
public string DepartmentFunction { get; set; }
public virtual ICollection<Branch> Branches { get; set; }
Employee:
public int ID { get; set; }
public string FirstName { get; set; }
public string SecondName { get; set; }
public double Salary { get; set; }
public DateTime StartingDate { get; set; }
public int BranchId { get; set; }
public int TitleId { get; set; }
Title:
public int ID { get; set; }
public string TitleName { get; set; }
public virtual ICollection<Employee> Employees { get; set; }
Thanks in advance
You're attempting to save employee details that reference a branch that doesn't exist. This is either because you haven't set the branch id at all, or you have set it to a number that is not present in the branch table Set the employees branch id to a branch that already exists. If no branches exist, create one. You should be able to create a branch and an employee simultaneously in code so long as the employee correctly refers to the branch. Entity framework should save the branch first so that it exists at the point it comes to save the employee
Related
I am trying to build an organization hierarchy where each team might contain one or many members and/or one or many sub-teams.
To do so, my model is:
public class Team
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Employee> Members { get; set; }
public virtual ICollection<Team> SubTeams { get; set; }
public Employee Manager { get; set; }
}
When adding a migration and updating database, everything seems logical in the table.
EF has added an extra nullable column "Team_Id" where the Id of the parent Team gets stored.
My question is about getting the Id of the parent Team from my model.
I tried adding:
public int? Team_Id
To my model, but EF considered it as a model change and asked for another migration.
How can I get the value of column Team_Id in my model? getting this info takes too much processing when looping through teams.
I always add foreign key in my model. When it adds to the model, EF won't add Team_Id .
public class Team
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Employee> Members { get; set; }
public virtual ICollection<Team> SubTeams { get; set; }
public Employee Manager { get; set; }
public int? ParentId { get; set; }
[ForeignKey("ParentId")]
public Team ParentTeam { get; set; }
}
I hope this example be helpful.
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.
Using ASPNET Boilerplate (.NET Framework) 3.6.1
I have successfully used the AsyncCrudAppService on a number of entities without issue, but I've hit an issue with one particular entity type that I can't insert, as Entity Framework seems to think it's being provided an explicit ID.
My Entity:
public class Attendance : FullAuditedEntity<int>
{
[Required]
public Guid Guid { get; set; }
public long? UserId { get; set; }
[Required]
public int EventId { get; set; }
public int StatusId { get; set; }
[Required]
[MaxLength(100)]
public string InviteEmail { get; set; }
[Required]
[MaxLength(20)]
public string InviteCode { get; set; }
public bool InviteAccepted { get; set; }
public DateTime? InviteAcceptedDate { get; set; }
public string InviteSource { get; set; }
public long? InvitedByUserId { get; set; }
[ForeignKey("UserId")]
public User User { get; set; }
[ForeignKey("InvitedByUserId")]
public User InvitedByUser { get; set; }
[ForeignKey("EventId")]
public Event Event { get; set; }
[ForeignKey("StatusId")]
public AttendanceStatus Status { get; set; }
}
My CreateDto
[AutoMapTo(typeof(Attendance))]
public class CreateAttendanceDto
{
public long? UserId { get; set; }
[Required]
public int EventId { get; set; }
public int StatusId { get; set; }
[Required]
[MaxLength(100)]
public string InviteEmail { get; set; }
public bool InviteAccepted { get; set; }
public DateTime? InviteAcceptedDate { get; set; }
public string InviteSource { get; set; }
public long? InvitedByUserId { get; set; }
}
My AppService Create method:
public override async Task<AttendanceDto> Create(CreateAttendanceDto input)
{
var attendance = ObjectMapper.Map<Attendance>(input);
attendance.InviteCode = "TEST";
// Create GUID
attendance.Guid = Guid.NewGuid();
await _attRepository.InsertAndGetIdAsync(attendance);
return MapToEntityDto(attendance);
}
Debugging the entity shows that is is sending id:0 to the insert method. This is exactly the same as another entity insert which is working fine.
Tracing the two different entity insert queries in SQL Profiler I can see that the working one has removed the ID from the insert query, where the one above that isn't working is trying to insert id=0 into the database, which is clearly a problem.
The error returned by the InsertAndGetIdAsync call as follows:
ERROR 2018-07-10 17:29:06,249 [108 ] nHandling.AbpApiExceptionFilterAttribute - An error occurred while updating the entries. See the inner exception for details.
System.Data.Entity.Infrastructure.DbUpdateException: An error occurred while updating the entries. See the inner exception for details. ---> System.Data.Entity.Core.UpdateException: An error occurred while updating the entries. See the inner exception for details. ---> System.Data.SqlClient.SqlException: Cannot insert explicit value for identity column in table 'Attendance' when IDENTITY_INSERT is set to OFF.
I've checked and double-checked for differences between these two appservice Creates and their related entities and dtos, and I can't find any differences. Even got a colleague to verify.
Any idea what might be going on here?
You need to specify a mapping for the entity Attendance so that it does not try to insert a value in the ID column. In simple terms, you need to makes EF aware that the ID column is configured for IDENTITY. The Exception message states this very clearly.
System.Data.SqlClient.SqlException: Cannot insert explicit value for identity column in table 'Attendance' when IDENTITY_INSERT is set to OFF.
Using attributes:
public class Attendance {
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long AttendanceId { get; set; }
}
or in fluent mapping in the DbContext type
protected override void OnModelCreating(DbModelBuilder modelBuilder) {
modelBuilder.Entity<Attendance>().Property(t => t.AttendanceId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
}
I found the issue, which was a little hidden.
Inside my DbContext I had previously attempted to give the Guid field a default value (which I now realise was also making it an identity column in the eyes of EF). In the end this didn't work but I'd neglected to tidy it up:
modelBuilder.Entity<Attendance>()
.Property(x => x.Guid)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
The database did not have any identity column on the Guid column, and the error related to the Id column, but clearly this was confusing EF's handling of the id value in the resulting query.
Removed the above code, rebuilt and all is working as it should.
Here are the business requirements, in short:
All employees need to be stored in a database
Some employees have assistants, some do not
Some employees have more than one assistant
Assistants are employees, as well
There is obviously a bit of a self-referencing situation. But the difference from a typical "Employee-Manager" situation is that here one Employee can have 0 or multiple assistants. So, the combination of Employee and employee's Assistants needs to be stored in a separate table in a one-to-many relationship between Employee and EmployeeAssistant. But I'm getting confused how to model this in Entity Framework 6 Code First.
I started with this:
public class Employee
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class EmployeeAssistant
{
[ForeignKey("Employee")]
public int EmployeeId { get; set; }
public virtual Employee Employee { get; set; }
[ForeignKey("Assistant")]
public int AssistantId { get; set; }
public virtual Employee Assistant { get; set; }
}
But I get an error during Update-Database command:
Introducing FOREIGN KEY constraint 'FK_dbo.EmployeeAssistant_dbo.Employee_EmployeeId' on table 'EmployeeAssistant' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
What am I missing? Should I approach this differently?
since each employee may have one or more assistants (and each assistant will have one or more employees) and all are employees, the simplest solution is one class with two collections for assistants and employees, and the relations will be managed by the framework:
public class Employee
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public ICollection<Employee> Assistants { get; set; }
public ICollection<Employee> Employees { get; set; }
}
when you use package manager console to add migration it will automatically create two tables, one for employees, and another for many to many relations.
then all you have to do is to find related assistants and/or employees by using Include extension method.
db.Employees.Where(x=>x.Id==id).Include(x=>x.Assistants).FirstOrDefault()
and/or
db.Employees.Where(x=>x.Id==id).Include(x=>x.Employees).FirstOrDefault()
Based on this link Introducing FOREIGN KEY constraint may cause cycles or multiple cascade paths - why?
It seems if you delete an EmployeeAssistant with your code, it causes two cascading delete paths.
I would suggest a structure such as this:
After edit
public class Employee
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public List<EmployeeAssistant> Assistants { get; set; } //if an employee has no assistants this List can easily just be empty
OR
public ICollection<EmployeeAssistant> Assistants { get; set; } // depending on your architecture, choose the one that would suit you better
}
public class EmployeeAssistant
{
[ForeignKey("Employee")]
public int EmployeeId { get; set; } //this is the employee who 'has' this assistant
public virtual Employee Employee { get; set; }
public int Id { get; set; } //this is the assistant's own information - identical to employee's basic info
public string FirstName { get; set; }
public string LastName { get; set; }
}
After a while of brain-boggling, I even came up with a possibility where you just need 1 class, Employee, but it includes a bool IsAssistant denoting if this employee is an assistant, and AssistantEmployeeId which is an employee ID of the employee who 'has' this assistant.
For example:
public class Employee
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public bool IsAssistant { get; set; }
public int EmployeeAssistantID { get; set; }
}
I know this second method is very messy and probably doesn't suit your needs, but personally I always create database tables first then do 'Generate Model from Database' so I'm inexperienced at code-first approach.
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.