Here is the case, I have 2 entities, such as Contract、Media。
public class Media : Entity
{
public string Name {get; set;}
public bool Enabled
*//other properties can be ignored..*
}
public class Contract : Entity
{
public string Code {get; set;}
*//other properties can be ignored..*
}
Contract has many Medias, it seems that they are many to many.
But!! at ef code first, i need 3 more fields in the ContractMedia table(ef auto generated).
such as StartDate,EndDate and Price. these could not be added in Media entity.
How to map at this case??
If you want to create many to many relationship with additional data in association table, you have to make the association table as entity. The pure many to many relationship is only in pure table with entity id's.
In you case it will be:
public class Media // One entity table
{
public int Id { get; set; }
public string Name { get; set; }
public bool Enabled { get; set; }
public virtual ICollection<ContractMedia> ContractMedias { get; set; }
}
public class Contract // Second entity table
{
public int Id { get; set; }
public string Code { get; set }
public virtual ICollection<ContractMedia> ContractMedias { get; set; }
}
public class ContractMedia // Association table implemented as entity
{
public int MediaId { get; set; }
public int ContractId { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public double Price { get; set; }
public virtual Media Media { get; set; }
public virtual Contract Contract { get; set; }
}
And after you created models/entities, you need to define relationships in context:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<ContractMedia>()
.HasKey(c => new { c.MediaId, c.ContractId });
modelBuilder.Entity<Contract>()
.HasMany(c => c.ContractMedias)
.WithRequired()
.HasForeignKey(c => c.ContractId);
modelBuilder.Entity<Media>()
.HasMany(c => c.ContractMedias)
.WithRequired()
.HasForeignKey(c => c.MediaId);
}
Also you can refer to these links:
Many to many mapping with extra fields in Fluent API
Entity Framework CodeFirst many to many relationship with additional information
Create code first, many to many, with additional fields in association table
Adding to #Tomas answer without having to use Fluent API.
public class Media // One entity table
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<ContractMedia> ContractMedias { get; set; }
}
public class Contract // Second entity table
{
public int Id { get; set; }
public string Code { get; set }
public virtual ICollection<ContractMedia> ContractMedias { get; set; }
}
public class ContractMedia // Association table implemented as entity
{
[Key]
[Column(Order = 0)]
[ForeignKey("Media")]
public int MediaId { get; set; }
[Key]
[Column(Order = 1)]
[ForeignKey("Contract")]
public int ContractId { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public double Price { get; set; }
public virtual Media Media { get; set; }
public virtual Contract Contract { get; set; }
}
EF Core needs to use Fluent API but it would look like this:
internal class MyContext : DbContext
{
public MyContext(DbContextOptions<MyContext> options)
: base(options)
{
}
public DbSet<Post> Posts { get; set; }
public DbSet<Tag> Tags { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Post>()
.HasMany(p => p.Tags)
.WithMany(p => p.Posts)
.UsingEntity<PostTag>(
j => j
.HasOne(pt => pt.Tag)
.WithMany(t => t.PostTags)
.HasForeignKey(pt => pt.TagId),
j => j
.HasOne(pt => pt.Post)
.WithMany(p => p.PostTags)
.HasForeignKey(pt => pt.PostId),
j =>
{
j.Property(pt => pt.PublicationDate).HasDefaultValueSql("CURRENT_TIMESTAMP");
j.HasKey(t => new { t.PostId, t.TagId });
});
}
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public ICollection<Tag> Tags { get; set; }
public List<PostTag> PostTags { get; set; }
}
public class Tag
{
public string TagId { get; set; }
public ICollection<Post> Posts { get; set; }
public List<PostTag> PostTags { get; set; }
}
public class PostTag
{
public DateTime PublicationDate { get; set; }
public int PostId { get; set; }
public Post Post { get; set; }
public string TagId { get; set; }
public Tag Tag { get; set; }
}
Source:
https://learn.microsoft.com/en-us/ef/core/modeling/relationships?tabs=fluent-api%2Cfluent-api-simple-key%2Csimple-key#join-entity-type-configuration
Related
I'm trying to create a many to many relation in the Fluent API with Ef Core 6 but i am having trouble understanding how to do so.
I've looked around here in stackoverflow but couldn't understand this relation and how to reproduce it in my code.
I have a table in my SQL database called People:
People.cs:
public class People : PeopleBase
{
public People()
{
RegistrationList = new HashSet<Registration>();
}
public virtual ICollection<Registration> RegistrationList { get; set; }
public virtual User User { get; set; }
public virtual ActivityGroup ActivityGroup { get; set; }
}
PeopleBase.cs:
public abstract class PeopleBase: ModelBase
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid PeopleId { get; set; }
public Guid? UserId { get; set; }
public Guid? ActivityGroupId { get; set; }
public string Code { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public PeopleActiveType Active { get; set; }
}
And then i have another table called ActivityGroup:
ActivityGroup.cs:
public class ActivityGroup : ActivityGroupBase
{
public ActivityGroup()
{
PeopleList = new HashSet<People>();
ActivityList = new HashSet<Activity>();
}
public ICollection<People> PeopleList { get; set; }
public ICollection<Activity> ActivityList { get; set; }
}
ActivityGroupBase.cs:
public abstract class ActivityGroupBase : ModelBase
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid ActivityGroupId { get; set; }
[Required]
[StringLength(20)]
public string Name { get; set; }
public StatusRecord Status { get; set; }
}
How would i do the mapping in the modelBuilder given that:
ActivityGroupId is the foreing key in the People database, pointing to the other table
One PeopleId can have multiple (many) ActivityGroupId
One ActivityGroupId can be assigned to multiple people.
What i've done so far:
modelBuilder.Entity<People>()
.HasOne(x => x.ActivityGroup)
.WithMany(x => x.PeopleList)
.HasForeignKey(x => x.ActivityGroupId);
Wouldn't i have to do this instead?
modelBuilder.Entity<People>()
.Hasmany(x => x.ActivityGroupList) //this is a ICollection<ActivityGroup> inside People class
.WithMany(x => x.PeopleList)
.HasForeignKey(x => x.ActivityGroupId); // this is not recognized by Ef Core
Can anyone help me please?
There are two main approaches for many-to-many relationships - with implicit junction table:
public class People : PeopleBase
{
// ...
public virtual List<Activity> Activities { get; set; }
}
public class Activity // : ...
{
// ...
public virtual List<People> PeopleList { get; set; }
}
modelBuilder.Entity<People>()
.HasMany(x => x.Activities)
.WithMany(x => x.PeopleList);
Or with explicit one:
public class People
{
// ...
public ICollection<PeopleActivity> PeopleActivities { get; set; }
}
public class Activity
{
// ...
public virtual ICollection<PeopleActivity> PeopleActivities { get; set; }
}
public class PeopleActivity
{
public Guid ActivityId { get; set; }
public Guid PeopleId { get; set; }
public Activity Activity { get; set; }
public People People { get; set; }
}
modelBuilder.Entity<PeopleActivity>()
.HasOne(pt => pt.People)
.WithMany(t => t.PeopleActivities)
.HasForeignKey(pt => pt.PeopleId);
Also maybe it worth changing entity name from People to Person (you can change table name with .ToTable("People") call)?
How to add multiple many-to-many relationships between Entities in EF Core 5.x, with join entity (linking tables)?
What I what is two many-to-many relationships between Card and Game. One relationship is not a problem but two (or more) I'm not able to configure it correctly.
What's working at the moment for me is that I created two different classes DeckGameCard and TableGameCard (join entity), which forces EF to create two tables. The classes are the same except for the name. Is it possible to have only one class (join entity) and two linking tables in the database?
What I want is this:
public class Game
{
[Key]
public int Id { get; set; }
public ICollection<GameCard> Deck { get; set; }
public ICollection<GameCard> OnTable { get; set; }
...
But at the moment this (the code below) is my solution (not optimal, because of code duplication in DeckGameCard and TableGameCard).
public class DeckGameCard
{
public int GameId { get; set; }
public Game Game { get; set; }
public int Order { get; set; }
public int CardId { get; set; }
public Card Card { get; set; }
}
public class TableGameCard
{
public int GameId { get; set; }
public Game Game { get; set; }
public int Order { get; set; }
public int CardId { get; set; }
public Card Card { get; set; }
}
public class Game
{
[Key]
public int Id { get; set; }
public ICollection<DeckGameCard> Deck { get; set; }
public ICollection<TableGameCard> OnTable { get; set; }
[Required]
public int CardIndex { get; set; }
[Required]
public int PlayerId { get; set; }
[Required]
public Player Player { get; set; }
}
public class Card : IEntity
{
[Key]
public int Id { get; set; }
[Required]
public Shape Shape { get; set; }
[Required]
public Fill Fill { get; set; }
[Required]
public Color Color { get; set; }
[Required]
public int NrOfShapes { get; set; }
public ICollection<DeckGameCard> Deck { get; set; }
public ICollection<TableGameCard> OnTable { get; set; }
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<DeckGameCard>()
.HasKey(x => new {x.GameId, x.CardId});
modelBuilder.Entity<DeckGameCard>()
.HasOne(gc => gc.Card)
.WithMany(b => b.Deck)
.HasForeignKey(gc => gc.CardId);
modelBuilder.Entity<DeckGameCard>()
.HasOne(gc => gc.Game)
.WithMany(g => g.Deck)
.HasForeignKey(gc => gc.GameId);
modelBuilder.Entity<TableGameCard>()
.HasKey(x => new {x.GameId, x.CardId});
modelBuilder.Entity<TableGameCard>()
.HasOne(gc => gc.Card)
.WithMany(b => b.OnTable)
.HasForeignKey(bc => bc.CardId);
modelBuilder.Entity<TableGameCard>()
.HasOne(gc => gc.Game)
.WithMany(g => g.OnTable)
.HasForeignKey(gc => gc.GameId);
}
Yes, it's possible by using the EF Core 5.0 introduced Shared-type entity types, but not sure it's worth since the type of an object no more uniquely identifies the entity type, so most if not all generic and non generic entity services (methods) of DbContext won't work, and you have to use the corresponding DbSet<T> methods, obtaining it using the Set<T>(name) overload. And there is no equivalent of Entry method, so you might have problems with change tracking in disconnected scenarios.
With that being said, here is how it can be done at model level.
Given the model similar to:
public class Game
{
public int Id { get; set; }
// ...
public ICollection<GameCard> Deck { get; set; }
public ICollection<GameCard> OnTable { get; set; }
}
public class Card
{
public int Id { get; set; }
// ...
public ICollection<GameCard> Deck { get; set; }
public ICollection<GameCard> OnTable { get; set; }
}
public class GameCard
{
public int GameId { get; set; }
public Game Game { get; set; }
public int Order { get; set; }
public int CardId { get; set; }
public Card Card { get; set; }
}
it can be configured as follows:
modelBuilder.SharedTypeEntity<GameCard>("DeckGameCard", builder =>
{
builder.ToTable("DeckGameCard");
builder.HasKey(e => new { e.GameId, e.CardId });
builder.HasOne(e => e.Card).WithMany(e => e.Deck);
builder.HasOne(e => e.Game).WithMany(e => e.Deck);
});
modelBuilder.SharedTypeEntity<GameCard>("TableGameCard", builder =>
{
builder.ToTable("TableGameCard");
builder.HasKey(e => new { e.GameId, e.CardId });
builder.HasOne(e => e.Card).WithMany(e => e.OnTable);
builder.HasOne(e => e.Game).WithMany(e => e.OnTable);
});
or since the only difference is the entity (table) name and the corresponding collection navigation properties, the configuration can be factored out to a method similar to
static void GameCardEntity(
ModelBuilder modelBuilder, string name,
Expression<Func<Card, IEnumerable<GameCard>>> cardCollection,
Expression<Func<Game, IEnumerable<GameCard>>> gameCollection,
string tableName = null
)
{
var builder = modelBuilder.SharedTypeEntity<GameCard>(name);
builder.ToTable(tableName ?? name);
builder.HasKey(e => new { e.GameId, e.CardId });
builder.HasOne(e => e.Card).WithMany(cardCollection);
builder.HasOne(e => e.Game).WithMany(gameCollection);
}
so the configuration becomes simply
GameCardEntity(modelBuilder, "DeckGameCard", c => c.Deck, g => g.Deck);
GameCardEntity(modelBuilder, "TableGameCard", c => c.OnTable, g => g.OnTable);
This should answer your concrete question. But again, make sure you understand the potential problems with it. And compare to "straight forward" solution achieving the same reusability with base class (not entity) without the above drawbacks, e.g.
public class Game
{
public int Id { get; set; }
// ...
public ICollection<DeskGameCard> Deck { get; set; }
public ICollection<TableGameCard> OnTable { get; set; }
}
public class Card
{
public int Id { get; set; }
// ...
public ICollection<DeskGameCard> Deck { get; set; }
public ICollection<TableGameCard> OnTable { get; set; }
}
public abstract class GameCard
{
public int GameId { get; set; }
public Game Game { get; set; }
public int Order { get; set; }
public int CardId { get; set; }
public Card Card { get; set; }
}
public class DeskGameCard : GameCard { }
public class TableGameCard : GameCard { }
with only fluent configuration needed for composite PK
modelBuilder.Entity<DeskGameCard>().HasKey(e => new { e.GameId, e.CardId });
modelBuilder.Entity<TableGameCard>().HasKey(e => new { e.GameId, e.CardId });
I'm trying to make a simple app to try Entity Framework Core, but i a have problem with setting up relations between entities. My entities:
public class Card
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public string Adress { get; set; }
public DateTime DoB { get; set; }
public DateTime DoS { get; set; }
public User Portal { get; set; }
public List<Reservation> Res { get; set; }
}
public class Doctor
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public string Email { get; set; }
public TimeSpan Start_Working { get; set; }
public TimeSpan End_Working { get; set; }
public List<Reservation> Reservations { get; set; }
public int SpecID { get; set; }
public Spec Spec { get; set; }
}
public class Reservation
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public DateTime DoR { get; set; }
public string Info { get; set; }
public int CardID { get; set; }
public Card Card_Nav_R { get; set; }
public int DoctorID { get; set; }
public Doctor Doctor { get; set; }
}
public class Spec
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Name { get; set; }
public List<Doctor> Doctors { get; set; }
}
public class User
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public int CardID { get; set; }
public Card Card { get; set; }
}
And a configuration class where i tried to set up relations:
class ApplicationContext:DbContext
{
public DbSet<User> Users { get; set; }
public DbSet<Card> Cards { get; set; }
public DbSet<Reservation> Reservations { get; set; }
public DbSet<Doctor> Doctors { get; set; }
public DbSet<Spec> Specs { get; set; }
public ApplicationContext()
{
Database.EnsureCreated();
}
protected override void OnModelCreating(ModelBuilder ModelBuilder)
{
ModelBuilder.Entity<User>().HasKey(u => u.Id);
ModelBuilder.Entity<Card>().HasKey(c => c.Id);
ModelBuilder.Entity<Doctor>().HasKey(d => d.Id);
ModelBuilder.Entity<Spec>().HasKey(s => s.Id);
ModelBuilder.Entity<Reservation>().HasKey(r => r.Id);
ModelBuilder.Entity<User>().Property(u => u.Email).IsRequired();
ModelBuilder.Entity<User>().Property(u => u.Password).IsRequired();
ModelBuilder.Entity<Card>().Property(c => c.Name).IsRequired();
ModelBuilder.Entity<Card>().Property(c => c.Surname).IsRequired();
ModelBuilder.Entity<Card>().Property(c => c.DoB).IsRequired();
ModelBuilder.Entity<Card>().Property(c => c.Adress).IsRequired();
ModelBuilder.Entity<Doctor>().Property(d => d.Name).IsRequired();
ModelBuilder.Entity<Doctor>().Property(d => d.Surname).IsRequired();
ModelBuilder.Entity<Doctor>().Property(d => d.Spec).IsRequired();
ModelBuilder.Entity<Doctor>().Property(d => d.Email).IsRequired();
ModelBuilder.Entity<Doctor>().Property(d => d.Start_Working).IsRequired();
ModelBuilder.Entity<Doctor>().Property(d => d.End_Working).IsRequired();
ModelBuilder.Entity<Reservation>().Property(r => r.Info).IsRequired();
ModelBuilder.Entity<Reservation>().Property(r => r.Card_Nav_R).IsRequired();
ModelBuilder.Entity<Reservation>().Property(r => r.Doctor).IsRequired();
ModelBuilder.Entity<Reservation>().Property(r => r.DoR).IsRequired();
ModelBuilder.Entity<Spec>().Property(s => s.Name).IsRequired();
ModelBuilder.Entity<Doctor>().HasOne<Spec>(d=>d.Spec).WithMany(s => s.Doctors).HasForeignKey(d => d.SpecID);
ModelBuilder.Entity<User>().HasOne<Card>(u => u.Card).WithOne(c => c.Portal).HasForeignKey<User>(u => u.CardID);
ModelBuilder.Entity<Reservation>().HasOne<Card>(r => r.Card_Nav_R).WithMany(c => c.Res).HasForeignKey(r => r.CardID);
ModelBuilder.Entity<Reservation>().HasOne<Doctor>(r => r.Doctor).WithMany(d => d.Reservations).HasForeignKey(r => r.DoctorID);
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Server=(localdb)\\mssqllocaldb;Database=Simple_Try;Trusted_Connection=True;");
}
}
So, when i tried to add migration or add something to database i saw this error:
System.InvalidOperationException: 'The property or navigation 'Spec' cannot be added to the entity type 'Doctor' because a property or navigation with the same name already exists on entity type 'Doctor'.'
I really don't know how to fix this, i tried to use annotations instead of Fluent API, but had the same result.
The cause of the exception is the following line:
ModelBuilder.Entity<Doctor>().Property(d => d.Spec).IsRequired();
because Doctor.Spec is a navigation property
public class Doctor
{
// ...
public Spec Spec { get; set; }
}
and navigation properties cannot be configured via Property fluent API.
So simply remove that line. Whether reference navigation property is required or optional is controlled via relationship configuration. In this case
ModelBuilder.Entity<Doctor>()
.HasOne(d => d.Spec)
.WithMany(s => s.Doctors)
.HasForeignKey(d => d.SpecID)
.IsRequired(); // <--
although the IsRequired is automatically derived from the FK property type - since SpecID is non nullable, then the relationship is required.
For more info, see Required and Optional Properties and Required and Optional Relationships documentation topics.
In my regular .NET Framework application, I was using EF 6.x and was also using some Inheritance, specifically:
PurchaseOrder.cs and SaleOrder.cs both inherit from Order.cs
And in the OnModelCreating() on my context class inheriting from IdentityDbContext, I was doing:
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
This used to work, but now I am moving my application to .NET Core 2.0 and I am using EF Core. What achieves the same thing in EF Core? Because right now I am getting the error:
System.Data.SqlClient.SqlException (0x80131904): Introducing FOREIGN KEY constraint 'FK_Order_Business_CustomerId' on table 'Order' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
UPDATE
Here's the code after Ahmar's answer. In my context class, I have:
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.HasDefaultSchema("PD");
builder.Entity<Customer>()
.HasMany(c => c.SaleOrders)
.WithOne(e => e.Customer)
.OnDelete(DeleteBehavior.SetNull);
builder.Entity<Supplier>()
.HasMany(po => po.PurchaseOrders)
.WithOne(e => e.Supplier)
.OnDelete(DeleteBehavior.SetNull);
builder.Entity<PurchaseOrder>()
.HasMany(li => li.LineItems)
.WithOne(po => po.PurchaseOrder)
.OnDelete(DeleteBehavior.SetNull);
builder.Entity<SaleOrder>()
.HasMany(li => li.LineItems)
.WithOne(po => po.SaleOrder)
.OnDelete(DeleteBehavior.SetNull);
}
And as far the Entities, they are:
public abstract class Business : IEntity
{
protected Business()
{
CreatedOn = DateTime.UtcNow;
}
public int Id { get; set; }
public string Name { get; set; }
public string TaxNumber { get; set; }
public string Description { get; set; }
public string Phone { get; set; }
public string Website { get; set; }
public string Email { get; set; }
public bool IsDeleted { get; set; }
public DateTime CreatedOn { get; set; }
public DateTime? ModifiedOn { get; set; }
public ICollection<Address> Addresses { get; set; } = new List<Address>();
public ICollection<Contact> Contacts { get; set; } = new List<Contact>();
}
[Table("Customers")]
public class Customer : Business
{
public decimal AllowedCredit { get; set; }
public decimal CreditUsed { get; set; }
public int NumberOfDaysAllowedToBeOnMaxedOutCredit { get; set; }
public ICollection<SaleOrder> SaleOrders { get; set; }
}
[Table("Suppliers")]
public class Supplier : Business
{
public ICollection<PurchaseOrder> PurchaseOrders { get; set; }
}
public abstract class Order : IEntity
{
protected Order()
{
Date = DateTime.UtcNow;
CreatedOn = DateTime.UtcNow;
}
public int Id { get; set; }
public DateTime Date { get; set; }
public decimal ShippingCost { get; set; }
public Currency ShippingCurrency { get; set; }
public decimal ShippingConversionRate { get; set; }
public bool IsDeleted { get; set; }
public DateTime CreatedOn { get; set; }
public DateTime? ModifiedOn { get; set; }
public ICollection<Invoice> Invoices { get; set; }
public ICollection<Note> Notes { get; set; }
}
[Table("PurchaseOrders")]
public class PurchaseOrder : Order
{
public int SupplierOrderNumber { get; set; }
public PurchaseOrderStatus Status { get; set; }
public decimal Vat { get; set; }
public decimal ImportDuty { get; set; }
public int SupplierId { get; set; }
public Supplier Supplier { get; set; }
public ICollection<PurchaseOrderLineItem> LineItems { get; set; }
}
[Table("SaleOrders")]
public class SaleOrder : Order
{
public decimal AmountToBePaidOnCredit { get; set; }
public SaleOrderStatus Status { get; set; }
public ICollection<SaleOrderLineItem> LineItems { get; set; }
public int CustomerId { get; set; }
public Customer Customer { get; set; }
}
So after doing what Ahmar suggested, I still get the same error when I do update-database.
You need to configure cascade delete behavior on each entity in .Net Core EF.
The Entity Framework Core Fluent API OnDelete method is used to specify the action which should take place on a dependent entity in a relationship when the principal is deleted.
The OnDelete method takes a DeleteBehavior enum as a parameter:
Cascade - dependents should be deleted
Restrict - dependents are
unaffected
SetNull - the foreign key values in dependent rows should
update to NULL
Example:
public class Company
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Employee> Employees { get; set; }
}
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public int? CompanyId { get; set; }
public Company Company { get; set; }
}
protected override void OnModelCreating(Modelbuilder modelBuilder)
{
modelBuilder.Entity<Company>()
.HasMany(c => c.Employees)
.WithOne(e => e.Company).
.OnDelete(DeleteBehavior.SetNull);
}
When deleting the Company, it will set CompanyId property in Employee table to null.
Get more detail at Configuring One To Many Relationships
PS. Please make sure your all referencing properties should be null able so, EF Core can set them null on delete. like CompanyId in about example.
I'm using CodeFirst for my devemopment. For all model classes in my Entity I have a base class named CommonFields
public class CommonFields
{
public int Status { get; set; }
public DateTime CreatedOn { get; set; }
public int CreaedBy { get; set; }
public DateTime ModifiedOn { get; set; }
public int ModifiedBy { get; set; }
}
And, for eg. I have two classes like
public class Employee : CommonFields
{
public int Id { get; set; }
public string Name { get; set; }
//Other properties
}
public class User : CommonFields
{
public int Id { get; set; }
public string Name { get; set; }
//Other properties
}
How can I set relation from CreatedBy & ModifiedBy to User table. I just need only one directional mapping.
I need to get User information when I write objEmployee.CreatedUser
Thanks.
public class CommonFields
{
public int Status { get; set; }
public DateTime CreatedOn { get; set; }
public int? CreatedById { get; set; }
public virtual User CreatedBy { get; set; }
public DateTime ModifiedOn { get; set; }
public virtual User ModifiedBy { get; set; }
public int? ModifiedById { get; set; }
}
and you have to define relations for all derived entities in your DbContext
protected override void OnModelCreating(DbModelBuilder mb)
{
mb.Entity<User>().HasOptional(x => x.CreatedBy).WithMany().HasForeignKey(x => x.CreatedById).WillCascadeOnDelete(false);
mb.Entity<User>().HasOptional(x => x.ModifiedBy).WithMany().HasForeignKey(x => x.ModifiedById).WillCascadeOnDelete(false);
mb.Entity<Employee>().HasOptional(x => x.CreatedBy).WithMany().HasForeignKey(x => x.CreatedById).WillCascadeOnDelete(false);
mb.Entity<Employee>().HasOptional(x => x.ModifiedBy).WithMany().HasForeignKey(x => x.ModifiedById).WillCascadeOnDelete(false);
}
EDIT:
Or you could use TPH. Then your model creating look like this
protected override void OnModelCreating(DbModelBuilder mb)
{
mb.Entity<CommonFields>().
.Map(x => x.ToTable("Users"))
.Map<User>(x => x.Requires("__type").HasValue(1)
.Map<Employee>(x => x.Requires("__type").HasValue(2);
mb.Entity<CommonFields>().HasOptional(x => x.CreatedBy).WithMany().HasForeignKey(x => x.CreatedById).WillCascadeOnDelete(false);
mb.Entity<CommonFields>().HasOptional(x => x.ModifiedBy).WithMany().HasForeignKey(x => x.ModifiedById).WillCascadeOnDelete(false);
}