I crete table in asp.net mvc but when i crete the migration this error message show
Introducing FOREIGN KEY constraint 'FK_dbo.DailyTransactions_dbo.Contracts_ContractId' on table 'DailyTransactions' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
Could not create constraint. See previous errors.
this is DailyTransactions table :
public class DailyTransactions
{
[Key]
public int DailyTransactions_Id { get; set; }
public double Account { get; set; }
public string Account_Name { get; set; }
public double Debit { get; set; }
public double Credit { get; set; }
public DateTime Date { get; set; }
public string Remarks { get; set; }
public int CustomerId { get; set; }
[ForeignKey("CustomerId")]
public virtual Customers customers { get; set; }
public int ContractId { get; set; }
[ForeignKey("ContractId")]
public virtual Contracts contracts { get; set; }
}
and this contract table :
public class Contracts
{
[Key]
public int Contracts_Id { get; set; }
public int Contract_Num { get; set; }
public DateTime Contract_Start { get; set; }
public DateTime Contract_End { get; set; }
public string Status { get; set; }
public string TypeOfRent { get; set; }
public double AmountOfRent { get; set; }
public double Total { get; set; }
public int CustomerId { get; set; }
[ForeignKey("CustomerId")]
public virtual Customers customers { get; set; }
public int sectionsId { get; set; }
[ForeignKey("sectionsId")]
public virtual Sections sections { get; set; }
}
Try to turn off CascadeDelete for DailyTransactions and Contracts:
modelBuilder.Entity<DailyTransactions>()
.HasRequired(c => c.Contracts)
.WithMany()
.WillCascadeOnDelete(false);
For example:
public class YourDBContext: DbContext
{
public YourDBContext(): base()
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<DailyTransactions>()
.HasRequired(c => c.Contracts)
.WithMany()
.WillCascadeOnDelete(false);
}
}
Related
How do I define the relationships here with EF Core?
I have an Employee table which has multiple Jobs
public class Employee
{
public int EmployeeId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public List<HourlyRate> DefaultRate { get; set; }
public string Note { get; set; }
public bool Active { get; set; }
public DateTime DateHired { get; set; }
public List<PhoneNumber> PhoneNumbers { get; set; }
public List<Address> Addresses { get; set; }
public List<Job> Jobs { get; set; }
public bool Deleted { get; set; }
}
And the Job class has an Employee object to navigate back to the employee and the Job has multiple Directors which are also Employees
public class Job
{
public int JobId { get; set; }
public Employee Employee { get; set; }
public JobType Type { get; set; }
public Department Department { get; set; }
public List<Employee> Directors { get; set; }
public bool Active { get; set; }
public decimal HourlyRate { get; set; }
public string Note { get; set; }
public bool Deduction { get; set; }
public int? DeductionPercent { get; set; }
}
This is my DbContext:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Employee>()
.HasMany(employee => employee.Jobs)
.WithOne(i => i.Employee);
}
Initially the Job only had a single Director and everything was good but the requirement has changed to have multiple directors and ef removed the Director column from the Job table and added a JobId column to the Employee table but the problem is that if i add that director to a second job by job.Directors.Add(director) EF overrides the job id of the of the director and the director is being removed from the previous job
I am using EF Core 2.2
if a Job has only 1 Employee but multiple Directors (also Employee)
add public int EmployeeId {get; set;} to your Job class and add this
modelBuilder
.Entity<Job>()
.HasMany(p => p.Directors)
.WithMany(p => p.Jobs));
also, change List<> to ICollection<>
You should tell EF through fluent API that there's a 1-to-many relationship from Employee to Job. Otherwise, EF may get confused.
The many-to-many relationship needs a junction table and matching entity in the model which you'll also need to configure through fluent API. You'll define two 1-to-many relationships from Employee and Job to that new entity. EF core does not directly support such relationships before 5.0.
If you are targeting SQL, then you need to mark at least one of the relationships as OnDelete(CascadeBehavior.NoAction). Otherwise, your model will generate invalid table defintions which will raise errors at creation time.
Update:
The junction table would be defined something like this.
public class Employee
{
// ... other stuff
public List<EmployeeJob> EmployeeJobs { get; set; }
}
public class Job
{
// ... other stuff
public List<EmployeeJob> EmployeeJobs { get; set; }
}
public class EmployeeJob
{
public int EmployeeId { get; set; }
public int JobId { get; set; }
public Employee Employee { get; set; }
public Job Job { get; set; }
}
// goes in DbContext
modelBuilder.Entity<EmployeeJob>.HasKey(x => new { x.EmployeeId, x.JobId });
Try to use this code. Since your employee can have one or many jobs I added the table EmployeeJob and many-to-many relations. I think you just need to add IsDirector flag to Employee or maybe better something like an EmployeeType:
public class Employee
{
public Employee()
{
EmployeeJobs = new HashSet<EmployeeJob>();
}
[Key]
public int EmployeeId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Note { get; set; }
public bool Active { get; set; }
public DateTime DateHired { get; set; }
public bool Deleted { get; set; }
[InverseProperty(nameof(EmployeeJob.Employee))]
public virtual ICollection<EmployeeJob> EmployeeJobs { get; set; }
}
public class Job
{
public Job()
{
EmployeeJobs = new HashSet<EmployeeJob>();
}
[Required]
public int JobId { get; set; }
public bool Active { get; set; }
public decimal HourlyRate { get; set; }
public string Note { get; set; }
public bool Deduction { get; set; }
public int? DeductionPercent { get; set; }
[InverseProperty(nameof(EmployeeJob.Job))]
public virtual ICollection<EmployeeJob> EmployeeJobs { get; set; }
}
public class EmployeeJob
{
[Key]
public int Id { get; set; }
public int EmployeeId { get; set; }
[ForeignKey(nameof(EmployeeId))]
[InverseProperty(nameof(EmployeeJob.Employee.EmployeeJobs))]
public virtual Employee Employee { get; set; }
public int JobId { get; set; }
[ForeignKey(nameof(JobId))]
[InverseProperty(nameof(EmployeeJob.Employee.EmployeeJobs))]
public virtual Job Job { get; set; }
}
public class EmployeeDbContext : DbContext
{
public EmployeeDbContext()
{
}
public EmployeeDbContext(DbContextOptions<EmployeeDbContext> options)
: base(options)
{
}
public DbSet<Employee> Employees { get; set; }
public DbSet<Job> Jobs { get; set; }
public DbSet<EmployeeJob> EmployeeJobs { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(#"Server=localhost;Database=Employee;Trusted_Connection=True;");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<EmployeeJob>(entity =>
{
entity.HasOne(d => d.Employee)
.WithMany(p => p.EmployeeJobs)
.HasForeignKey(d => d.EmployeeId)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_EmployeeJob_Employee");
entity.HasOne(d => d.Job)
.WithMany(p => p.EmployeeJobs)
.HasForeignKey(d => d.JobId)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_EmployeeJob_Job");
});
}
I have User table and I'd like to add connection called UserFriend between 2 users. I've searched a lot and basicly tried many different solutions and none of them worked. Everytime I get same error:
Introducing FOREIGN KEY constraint 'FK_UserFriends_Users_Friend2Id' on table 'UserFriends' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
Here are my models:
public class User
{
[Key]
public Guid Id { get; set; }
public string Username { get; set; }
public string EmailAddress { get; set; }
public string Firstname { get; set; }
public string Lastname { get; set; }
public virtual ICollection<UserFriend> Friends { get; set; }
public virtual ICollection<UserFriend> FriendOf { get; set; }
}
public class UserFriend
{
public User Friend1 { get; set; }
public Guid Friend1Id { get; set; }
public User Friend2 { get; set; }
public Guid Friend2Id { get; set; }
public bool Confirmed { get; set; }
public DateTime Added { get; set; }
}
And here's code in DataContext:
modelBuilder.Entity<UserFriend>().HasKey(sc => new { sc.Friend1Id, sc.Friend2Id });
modelBuilder.Entity<UserFriend>()
.HasOne(c => c.Friend1)
.WithMany(c => c.FriendOf)
.HasForeignKey(f => f.Friend1Id);
modelBuilder.Entity<UserFriend>()
.HasOne(c => c.Friend2)
.WithMany(c => c.Friends)
.HasForeignKey(f => f.Friend2Id)
.OnDelete(DeleteBehavior.Restrict);
Change your code to below and remove the other lines you have posted.
public class User
{
[Key]
public Guid Id { get; set; }
public string Username { get; set; }
public string EmailAddress { get; set; }
public string Firstname { get; set; }
public string Lastname { get; set; }
public virtual ICollection<UserFriend> Friends { get; set; }
public virtual ICollection<UserFriend> FriendOf { get; set; }
}
public class UserFriend
{
public User Friend1 { get; set; }
[ForeignKey("Friend1")]
public Guid? Friend1Id { get; set; }
public User Friend2 { get; set; }
[ForeignKey("Friend2")]
public Guid? Friend2Id { get; set; }
public bool Confirmed { get; set; }
public DateTime Added { get; set; }
}
modelBuilder.Entity<User>();
modelBuilder.Entity<UserFriend>();
I have two classes:
One is User
public class User
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public List<Subscription> Subscriptions { get; set; }
}
Other is Subscription:
public class Subscription
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
As you can see that User has a list of Subscriptions.
Now when using the entity framework code first approach I am getting a table for User which doesn't contain Subscriptions but a new column for User Id is being added to Subscription table. I was expecting to have a third table which contains two columns one with User ID and the other with subscription ID.
How can I achieve this?
From documentation:
Many-to-many relationships without an entity class to represent the join table are not yet supported. However, you can represent a many-to-many relationship by including an entity class for the join table and mapping two separate one-to-many relationships.
So this answer is correct.
I just corrected code a little bit:
class MyContext : DbContext
{
public DbSet<Use> Users { get; set; }
public DbSet<Subscription> Subscriptions { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<UserSubscription>()
.HasKey(t => new { t.UserId, t.SubscriptionId });
modelBuilder.Entity<UserSubscription>()
.HasOne(pt => pt.User)
.WithMany(p => p.UserSubscription)
.HasForeignKey(pt => pt.UserId);
modelBuilder.Entity<UserSubscription>()
.HasOne(pt => pt.Subscription)
.WithMany(t => t.UserSubscription)
.HasForeignKey(pt => pt.SubscriptionId);
}
}
public class User
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public List<UserSubscription> UserSubscriptions{ get; set; }
}
public class Subscription
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public List<UserSubscription> UserSubscriptions{ get; set; }
}
public class UserSubscription
{
public int UserId { get; set; }
public User User { get; set; }
public int SubscriptionId { get; set; }
public Subscription Subscription { get; set; }
}
PS. You don't need use virtual in navigation property, because lazy loading still not available in EF Core.
Create a third middle table named: UserSubscriptions for example.
public class User
{
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public virtual ICollection<UserSubscription> Subscriptions { get; set; }
}
public class Subscription
{
public int ID { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
public class UserSubscription
{
public int ID { get; set; }
public int SubscriptionID { get; set; }
public decimal Price { get; set; }
public int UserID { get; set; }
public virtual User { get; set; }
public DateTime BeginDate { get; set; }
public DateTime EndDate { get; set; }
}
Second Solution:
Add reference for Subscription to User and name it CurrentSubscription for example.
public class User
{
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public int CurrentSubscriptionID { get; set; }
public virtual Subscription Subscription { get; set; }
}
public class Subscription
{
public int ID { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
I have some classes:
public class Values : Entity
{
[Key]
public int Values_ID { get; set; }
[Required]
public string Values_Name { get; set; }
[Required]
public int ValuesNumeric { get; set; }
public virtual ICollection<ValuesMetrics> ValuesMetrics { get; set; }
}
public class GQMetric : Entity
{
[Key]
public int GQMetric_ID { get; set; }
[Required]
public string GQMetricName { get; set; }
[Required]
public int Importance_ID { get; set; }
public virtual List<GQMetricsQuestions> GQMetricsQuestions { get; set; }
public virtual ICollection<ValuesMetrics> ValuesMetrics { get; set; }
public virtual ImportanceScale ImportanceScale { get; set; }
}
I need to create many-to-many relationship to my own created class ValuesMetrics, not to automatically generated table by entity framework. I have tried a lot of solutions here, here and here but none of it did not work. Eventually, I did this:
public class ValuesMetrics : Entity
{
public int GQMetric_ID { get; set; }
public int Value_ID { get; set; }
public virtual GQMetric GQMetric { get; set; }
public virtual Values Values { get; set; }
}
FluentAPI:
modelBuilder.Entity<ValuesMetrics>()
.HasKey(c => new { c.GQMetric_ID, c.Value_ID });
modelBuilder.Entity<GQMetricsQuestions>()
.HasKey(c => new { c.GQMetric_ID, c.Question_ID });
but created table (ValuesMetrics) have an excessive relationship (GQMetrics_GQMetric_ID). I need only two primary keys from Values and GQMetrics tables
Can you advice me how to solve this problem? Thanks for any help!
Applied #Esteban 's solution from the link already referenced by you: Create code first, many to many, with additional fields in association table
Basically I did the following three changes:
Used POCO entities instead of inheriting from Entity class
Removed EF attributes, since we'll be using fluent API anyway
Changed fluent API configuration
Resulting code:
public class MyContext : DbContext
{
public DbSet<Values> Values { get; set; }
public DbSet<GQMetric> GqMetric { get; set; }
public DbSet<ValuesMetrics> ValuesMetrics { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Values>().HasKey(values => values.Values_ID);
modelBuilder.Entity<GQMetric>().HasKey(metric => metric.GQMetric_ID);
modelBuilder
.Entity<ValuesMetrics>()
.HasKey(valuesMetrics => new
{
valuesMetrics.Value_ID,
valuesMetrics.GQMetric_ID
});
modelBuilder
.Entity<ValuesMetrics>()
.HasRequired(valuesMetrics => valuesMetrics.Values)
.WithMany(valueMetrics => valueMetrics.ValuesMetrics)
.HasForeignKey(valueMetrics => valueMetrics.Value_ID);
modelBuilder
.Entity<ValuesMetrics>()
.HasRequired(valuesMetrics => valuesMetrics.GQMetric)
.WithMany(valueMetrics => valueMetrics.ValuesMetrics)
.HasForeignKey(valueMetrics => valueMetrics.GQMetric_ID);
base.OnModelCreating(modelBuilder);
}
}
public class Values
{
public int Values_ID { get; set; }
public string Values_Name { get; set; }
public int ValuesNumeric { get; set; }
public virtual ICollection<ValuesMetrics> ValuesMetrics { get; set; }
}
public class GQMetric
{
public int GQMetric_ID { get; set; }
public string GQMetricName { get; set; }
public virtual ICollection<ValuesMetrics> ValuesMetrics { get; set; }
}
public class ValuesMetrics
{
public int GQMetric_ID { get; set; }
public int Value_ID { get; set; }
public virtual GQMetric GQMetric { get; set; }
public virtual Values Values { get; set; }
}
I am using Entity framework 4.1 in MVC 3 application. I have an entity where I have primary key consists of two columns ( composite key). And this is being used in another entity as foreign key. How to create the relationship ? In normal scnerios we use :
public class Category
{
public string CategoryId { get; set; }
public string Name { get; set; }
public virtual ICollection<Product> Products { get; set; }
}
public class Product
{
public int ProductId { get; set; }
public string Name { get; set; }
public string CategoryId { get; set; }
public virtual Category Category { get; set; }
}
but what if category has two columns key ?
You can use either fluent API:
public class Category
{
public int CategoryId1 { get; set; }
public int CategoryId2 { get; set; }
public string Name { get; set; }
public virtual ICollection<Product> Products { get; set; }
}
public class Product
{
public int ProductId { get; set; }
public string Name { get; set; }
public int CategoryId1 { get; set; }
public int CategoryId2 { get; set; }
public virtual Category Category { get; set; }
}
public class Context : DbContext
{
public DbSet<Category> Categories { get; set; }
public DbSet<Product> Products { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Category>()
.HasKey(c => new {c.CategoryId1, c.CategoryId2});
modelBuilder.Entity<Product>()
.HasRequired(p => p.Category)
.WithMany(c => c.Products)
.HasForeignKey(p => new {p.CategoryId1, p.CategoryId2});
}
}
Or data annotations:
public class Category
{
[Key, Column(Order = 0)]
public int CategoryId2 { get; set; }
[Key, Column(Order = 1)]
public int CategoryId3 { get; set; }
public string Name { get; set; }
public virtual ICollection<Product> Products { get; set; }
}
public class Product
{
[Key]
public int ProductId { get; set; }
public string Name { get; set; }
[ForeignKey("Category"), Column(Order = 0)]
public int CategoryId2 { get; set; }
[ForeignKey("Category"), Column(Order = 1)]
public int CategoryId3 { get; set; }
public virtual Category Category { get; set; }
}
I believe the easiest way is to use Data Annotation on the Navigation property like this:
[ForeignKey("CategoryId1, CategoryId2")]
public class Category
{
[Key, Column(Order = 0)]
public int CategoryId1 { get; set; }
[Key, Column(Order = 1)]
public int CategoryId2 { get; set; }
public string Name { get; set; }
public virtual ICollection<Product> Products { get; set; }
}
public class Product
{
[Key]
public int ProductId { get; set; }
public string Name { get; set; }
public int CategoryId1 { get; set; }
public int CategoryId2 { get; set; }
[ForeignKey("CategoryId1, CategoryId2")]
public virtual Category Category { get; set; }
}
In .NET Core and .NET 5 < the documentation only shows Data annotations (simple key).
https://learn.microsoft.com/en-us/ef/core/modeling/relationships?tabs=fluent-api%2Cfluent-api-composite-key%2Csimple-key#foreign-key
However using the example from #LadislavMrnka you will get a error message like this:
System.InvalidOperationException: There are multiple properties with
the [ForeignKey] attribute pointing to navigation ''. To define a
composite foreign key using data annotations, use the [ForeignKey]
attribute on the navigation.
Using that error message you can write the code like this:
public class Product
{
[Key]
public int ProductId { get; set; }
public string Name { get; set; }
public int CategoryId2 { get; set; }
public int CategoryId3 { get; set; }
[ForeignKey("CategoryId2,CategoryId3")]
public virtual Category Category { get; set; }
}
Fluent API (composite key) example from Microsoft:
internal class MyContext : DbContext
{
public DbSet<Car> Cars { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Car>()
.HasKey(c => new { c.State, c.LicensePlate });
modelBuilder.Entity<RecordOfSale>()
.HasOne(s => s.Car)
.WithMany(c => c.SaleHistory)
.HasForeignKey(s => new { s.CarState, s.CarLicensePlate });
}
}
public class Car
{
public string State { get; set; }
public string LicensePlate { get; set; }
public string Make { get; set; }
public string Model { get; set; }
public List<RecordOfSale> SaleHistory { get; set; }
}
public class RecordOfSale
{
public int RecordOfSaleId { get; set; }
public DateTime DateSold { get; set; }
public decimal Price { get; set; }
public string CarState { get; set; }
public string CarLicensePlate { get; set; }
public Car Car { get; set; }
}