Entity Framework Core cascade on delete, - c#

I try to configure my entities that they will have appropriate relations.
I want to configure it that, when I remove category entity, it should disappear from database with its translation and all of products of this category(including products translations of course).
It works but not fully.
At this moment when I remove category, all products of this category are removed, but translations(category and products) stays.
My entities:
public class Product
{
public Guid Id { get; protected set; }
public Category Category { get; protected set; }
public Translation Translation { get; protected set; }
}
public class Category
{
public Guid Id { get; protected set; }
public IEnumerable<Product> Products { get; protected set; }
public Translation Translation { get; protected set; }
}
public class Translation
{
public Guid Id { get; protected set; }
public string English { get; protected set; }
public string Polish { get; protected set; }
public string Gernam { get; protected set; }
}
DbContext configuration
modelBuilder.Entity<Category>().HasMany(x => x.Products).WithOne(x => x.Category)
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<Product>().HasOne(x => x.Category).WithMany(x => x.Products)
.OnDelete(DeleteBehavior.Cascade);
It it possible to configure dbcontext that it will works as I want WITHOUT adding Category, and Product properties to Translation entity?

Related

Entity Created OnModelCreating is not accessible in DbContext

I have a many to many relationship mapping, and the mapping table has an additional field. I created the ApplicationDbContext as below:
public virtual DbSet<Country> Countries { get; set; }
public virtual DbSet<Region> Regions { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<CountryRegionMapping>()
.HasKey(um => um.CountryRegionMappingId)
.ToTable("CountryRegionMapping");
modelBuilder.Entity<CountryRegionMapping>()
.HasRequired(um => um.Region).WithMany(g => g.CountryMappings)
.HasForeignKey(um => um.RegionId);
modelBuilder.Entity<CountryRegionMapping>()
.HasRequired(um => um.Country).WithMany(g => g.RegionMappings)
.HasForeignKey(um => um.CountryId);
base.OnModelCreating(modelBuilder);
}
I was refering this link to create the Many-to-Many relationship having an extra field in the mapping table.
The entity classes are :
public class Country
{
public int Id { get; set; }
public string SystemOneName { get; set; }
public string SystemTwoName { get; set; }
public virtual ICollection<CountryRegionMapping> RegionMappings { get; set; }
}
public class Region
{
public int Id { get; set; }
public string SystemOneName { get; set; }
public string SystemTwoName { get; set; }
public virtual ICollection<CountryRegionMapping> CountryMappings { get; set; }
}
public class CountryRegionMapping
{
public int CountryRegionMappingId { get; set; }
public int CountryId { get; set; }
public virtual Country Country { get; set; }
public int RegionId { get; set; }
public virtual Region Region { get; set; }
public bool CheckField { get; set; }
}
When I try to access the Country or Region tables I can simply access it through the code as below using dbcontext.Regions
ApplicationDbContext db = new ApplicationDbContext();
db.Regions.SingleOrDefault(r => r.Id == Id);
But when I try to access the "CountryRegionMapping" entity I cannot access through a code as db.CountryRegionMapping
Why is this not available in the Db Context. How can I access this entity in the middle of a Many-to-Many relationship.
If you want to access the middle-mapping entities directly, add those as a DbSet on your context, along with the other ones:
public virtual DbSet<CountryRegionMapping> CountryRegionMappings { get; set; }
public virtual DbSet<Country> Countries { get; set; }
public virtual DbSet<Region> Regions { get; set; }
Then you can access them same as you access Countries, or Regions:
ApplicationDbContext db = new ApplicationDbContext();
db.CountryRegionMappings//.SingleOrDefault, etc.

Work with many-to many relationships C#

Good evening!
I use Asp.net MVC with EF.
I have 2 models
public class Product
{
public int ID { get; set; }
public string Name { get; set; }
public ICollection<Category> categories { get; set; }
}
public class Category
{
public int ID { get; set; }
public string Name { get; set; }
public ICollection<Product> products { get; set; }
}
many-to many add normaly work, if I add new product, but if i try update product entity,new relationship doesnt add.
I add new products like this
Product product= new Product{...};
product.categories.Add(db.Categories.First())//example
How I can add/delete relationships in product entity update?
First, your ICollection<T> should be a virtual property:
public class Product
{
public int ID { get; set; }
public string Name { get; set; }
public virtual ICollection<ProductCategory> ProductCategories { get; set; }
}
public class Category
{
public int ID { get; set; }
public string Name { get; set; }
public virtual ICollection<ProductCategory> ProductCategories { get; set; }
}
Next, create an association table between the two:
public class ProductCategory
{
public virtual Product Product { get; set; }
public virtual Category Category { get; set; }
}
Then in your dbContext, add the relationships:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<ProductCategory>()
.HasKey(c => new { c.CategoryId, c.ProductId });
modelBuilder.Entity<Product>()
.HasMany(c => c.ProductCategories)
.WithRequired()
.HasForeignKey(c => c.ProductId);
modelBuilder.Entity<Category>()
.HasMany(c => c.ProductCategories)
.WithRequired()
.HasForeignKey(c => c.CategoryId);
}

2 Foreign Keys, 1 Navigation Property to pull through both

Given the following rough code-first schema, the goal would appear to be quite simple. An Invoice can either be from or to a Company, and the Invoices collection should contain all invoices regardless of which it is.
public class Company
{
public int Id { get; set; }
public virtual ICollection<Invoice> Invoices { get; set; }
}
public class Invoice
{
public int Id { get; set; }
public int FromCompanyId { get; set; }
public int ToCompanyId { get; set; }
public virtual Company FromCompany { get; set; }
public virtual Company ToCompany { get; set; }
}
You'll note in a Migration that a third Company_Id is generated for obvious reasons to support the Invoices navigation property as EF only appears to support a 1 Nav Prop -> 1 FK arrangement.
My question is whether or not it is possible to have the Invoices property contain both, or if I should map them individually (ie. IC<Inv> InvoicesFrom, IC<Inv> InvoicesTo) and create a client-side collection to have both manually.
I have tried:
Using InverseProperty on both FromCompany and ToCompany, which confuses EF as it can't determine the principal end of the relationship.
[ForeignKey(nameof(FromCompanyId)), InverseProperty(nameof(Company.Invoices))]
public virtual Company FromCompany { get; set; }
[ForeignKey(nameof(ToCompanyId)), InverseProperty(nameof(Company.Invoices))]
public virtual Company ToCompany { get; set; }
Using fluent API to map them, but it only takes into account the second which makes sense from a code perspective.
modelBuilder.Entity<Company>()
.HasMany(m => m.Invoices)
.WithRequired(m => m.ToCompany)
.WillCascadeOnDelete(false);
modelBuilder.Entity<Company>()
.HasMany(m => m.Invoices)
.WithRequired(m => m.FromCompany)
.WillCascadeOnDelete(false);
There's of course no major issue if this isn't possible, I just could have sworn I've done it before.
For posterity, here is a complete version of the workaround to maintain an IEnumerable<Invoices> from company that contains both of the sets put together.
public class MyContext : DbContext
{
public MyContext() : base("DefaultConnection") { }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Company>().HasMany(c => c.InvoicesFrom).WithRequired(i => i.FromCompany).WillCascadeOnDelete(false);
modelBuilder.Entity<Company>().HasMany(c => c.InvoicesTo).WithRequired(i => i.ToCompany).WillCascadeOnDelete(false);
}
public DbSet<Company> Companies { get; set; }
public DbSet<Invoice> Invoices { get; set; }
}
public class Company
{
public int Id { get; set; }
public virtual ICollection<Invoice> InvoicesFrom { get; set; }
public virtual ICollection<Invoice> InvoicesTo { get; set; }
[NotMapped]
public IEnumerable<Invoice> Invoices
{
get {
return InvoicesFrom.Union(InvoicesTo);
}
}
}
public class Invoice
{
public int Id { get; set; }
public int FromCompanyId { get; set; }
public int ToCompanyId { get; set; }
public virtual Company FromCompany { get; set; }
public virtual Company ToCompany { get; set; }
}

EF6 doesn't generate Entity Data Model as expected

I have two entities. Event and User. I want to save the creator (= user) of the event as contact in my Event entity. Additionally i want to have several guides (= user as well) associated with my event.
This is (part of) my code:
public class User
{
public int ID { get; set; }
public string LoginName { get; set; }
public string DisplayName { get; set; }
public virtual ICollection<Event> Events { get; set; }
}
public class Event
{
public int ID { get; set; }
public string EventName { get; set; }
public User ContactName { get; set; }
public virtual ICollection<Room> Rooms { get; set; }
public virtual ICollection<User> Users { get; set; } // These are the guides
public virtual ICollection<Equipment> Equipments { get; set; }
[Required]
public EventType Type { get; set; }
}
I'm expecting EF6 (6.1.3) to create 1:n and n:m relationships between User and Event. What it does instead can be seen in the screenshot below:
There is one 1:n relation - as expected. But instead of one n:m relation there is one 1:n and one n:1 relationship. Please help.
For many to many link, You have to write it in the function :
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.HasMany<Event>(s => s.Events)
.WithMany(c => c.Users)
.Map(cs =>
{
cs.MapLeftKey("UserRefId");
cs.MapRightKey("EventRefId");
cs.ToTable("UserEvent");
});
}
It's imply a new table between the two others
You can follow this guide
There isnt a foreign key relation mapped in Event class:
public class Event
{
public int ID { get; set; }
public string EventName { get; set; }
public int ContactId {get ; set;}
[ForeignKey("ContactId")]
public virtual User Contact { get; set; }
public virtual ICollection<Room> Rooms { get; set; }
public virtual ICollection<User> Users { get; set; } // These are the guides
public virtual ICollection<Equipment> Equipments { get; set; }
[Required]
public EventType Type { get; set; }
}

Error -"Could not drop constraint" when execute .AsQueryable();

I am using EF code first to generate many to many relation. as the following:
public class User
{
public User()
{
Categories = new Collection<Category>();
}
public int UserId { get; set; }
public string LastName { get; set; }
public ICollection<Category> Categories { get; set; }
}
and
public sealed class Category
{
public Category()
{
Users = new Collection<User>();
}
public string Name { get; set; }
public int Id { get; set; }
public ICollection<User> Users { get; set; }
}
My Db context look like:
public DbSet<User> Users { get; set; }
public DbSet<Category> Categories { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<User>().HasMany(b => b.Categories).WithMany(a => a.Users).Map(m => m.MapLeftKey("userId").MapRightKey("id"));
base.OnModelCreating(modelBuilder);
}
The weird issue is when Im doing simple action like:
_ctx.Categories.AsQueryable();
I get the following error:
The constraint 'PK_dbo.Categories' is being referenced by table 'UserCategories', foreign key constraint 'FK_dbo.CategoryUsers_dbo.Categories_id'.
Could not drop constraint. See previous errors.

Categories