i am having troubles trying to figure out how to rename and configure an autogenerated table, from entity framework.
Here is my code :
public class ApplicationUser : IdentityUser
{
public virtual List<ApplicationUser> AddingFriends { get; set; }
public virtual List<ApplicationUser> AddedFriends { get; set; }
}
There result expressed by those entities once migrate to the database is as the following :
So i basically just want to rename this table and it's columns names.
Besides that i also want to create a second table for bloqued people wich would have the same lists of entities. So basically when i add two other lists of application users it binds those property to this actual table shown below.
Is there a way to control those table generation and configure them correctly?
Thanks in advance. Cheers.
You are using code first approach and this keeps track of the model and database table corresponding to that model.So, You cannot change the model.Options are to enable migration or to disable model checking.
check this link for migrationhttps://learn.microsoft.com/en-us/aspnet/mvc/overview/getting-started/getting-started-with-ef-using-mvc/migrations-and-deployment-with-the-entity-framework-in-an-asp-net-mvc-application
After looking at the Fluent API Documentation i found that i could configure that with by adding those lines of code to OnModelCreating method:
modelBuilder.Entity<ApplicationUser>()
.HasMany(c => c.AddedFriends)
.WithMany(c => c.AddingFriends)
.Map(m =>
{
m.ToTable("Friends");
m.MapLeftKey("AddedUser");
m.MapRightKey("AddingUser");
});
modelBuilder.Entity<ApplicationUser>()
.HasMany(c => c.BloquedUsers)
.WithMany(c => c.BloquingUsers)
.Map(m =>
{
m.ToTable("Bloqueds");
m.MapLeftKey("BloquingUser");
m.MapRightKey("BloquedUser");
});
Thanks for your answers.
Related
The join table of a many-to-many relationship in my Xamarin.Forms application seems to not be cleared correctly when deleting one of the two entities.
I have these classes:
public class Input
{
// One-to-many
public ObservableCollection<InputResult> InputResults { get; set; }
//...
// Here are many more entities which shouldn't be relevant for this example
//...
}
public class InputResult
{
// One-to-many
public string ParentInputId { get; set;}
// Many-to-many
public ObservableCollection<MyDropdown> MyDropdowns { get; set; }
}
public class MyDropdown
{
// Many-to-many
public ObservableCollection<InputResult> InputResults { get; set; }
}
I configured the relationships in my DbContext class like this:
modelBuilder.Entity<Input>()
.HasMany(b => b.InputResults)
.WithOne()
.HasForeignKey(b => b.ParentInputId)
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<InputResult>()
.HasMany(b => b.MyDropdowns)
.WithMany(b => b.InputResults);
Let's say I have previously loaded an Input with its InputResults. Then I delete the InputResults in a helper class like that:
Context.RemoveRange(Input.InputResults);
The InputResults get deleted correctly. When I look into the SQLite database directly I still see all the entries in the join table of InputResults and MyDropdown. Why are there still entries? Yesterday one of our users got a unique constraint error after deleting some data and trying to insert the same data again.
I appreciate any help.
Edit:
To expand my comment on CSharp's answer:
I can't use OnDelete(DeleteBehavior.Cascade) when configuring the DbContext. It seems as EF Core did this correctly by itself though. The part of the join table in the DatabaseContextModelSnapshot.cs looks like this:
modelBuilder.Entity("InputResultMyDropdown", b =>
{
b.HasOne("Inputs.MyDropdown", null)
.WithMany()
.HasForeignKey("MyDropdownId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Inputs.InputResult", null)
.WithMany()
.HasForeignKey("InputResultId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
There should be a cascade delete behavior in DbContext:
modelBuilder.Entity<InputResult>()
.HasMany(b => b.MyDropdowns)
.WithMany(b => b.InputResults)
.OnDelete(DeleteBehavior.Cascade);
I have two entities, Tag and Member. A member can be marked with multiple tags. A tag can be used to mark multiple members. It's a clear case of many-to-many relation and since I'm using EF Core, I have to declare an explicit connector, which I call Tag_Member. I configure it in the following way.
private void OnModelCreating(EntityTypeBuilder<Tag_Member> entity)
{
entity.HasKey(e => new { e.TagId, e.MemberId });
entity.HasOne(e => e.Tag);
entity.HasOne(e => e.Member)
.WithMany(e => e.Tag_Member)
.HasForeignKey(e => e.MemberId);
}
The behavior I wish to enforce when deleting is as follows.
When removing an instance of Tag_Member, nothing is changed.
When removing an instance of Tag, any connected instances of Tag_Member are deleted.
When removing an instance of Member, any connected instances of Tag_Member are deleted.
I'm confused on two points. When I add the condition for deletion as shown below, I have a lot of options to pick from and, despite reading the intellisense, I don't feel certain which to use to enforce the above behavior.
entity.HasOne(e => e.Member)
.WithMany(e => e.Tag_Member)
.HasForeignKey(e => e.MemberId)
.OnDelete(DeleteBehavior.NoAction);
Should I use NoAction, ClientNoAction, Restrict or someting else? I'm not even clear on which of hte entities that the deletetion behavior affects. Which is it?
The second point of confusion is that I don't get OnDelete() to appear for the tag configuration. I haven't used WithMany() because that entity lacks references back to the interlinking entity. Can I still manage its deletion behavior? Do I need to explicitly declare it to achieve the requested behavior?
entity.HasOne(e => e.Tag)
.OnDelete(DeleteBehavior.NoAction);
The classes look roughly like this.
public class Tag { public Guid Id { get; set; } }
public class Member { public Guid Id { get; set; } }
public class Tag_Member
{
public Guid TagId { get; set; }
public Guid MemberId { get; set; }
public Tag Tag { get; set; }
public Member Member { get; set; }
}
My references are mainly this and this.
edit: Based on the suggestions in the answer, this is the final version of the relation between members and tag.
private static void OnModelCreating(EntityTypeBuilder<Member> entity)
{
entity.HasKey(e => e.Id); ...
}
private static void OnModelCreating(EntityTypeBuilder<Tag> entity)
{
entity.HasKey(e => e.Id); ...
}
private static void OnModelCreating(EntityTypeBuilder<Member_Tag> entity)
{
entity.HasKey(e => new { e.MemberId, e.TagId });
entity.HasOne(e => e.Member).WithMany().OnDelete(DeleteBehavior.NoAction);
entity.HasOne(e => e.Tag).WithMany().OnDelete(DeleteBehavior.NoAction);
}
I'm not even clear on which of hte entities that the deletetion behavior affects. Which is it?
That's easy. The cascade delete always affects the dependent entity (i.e. the entity containing the FK).
I don't feel certain which to use to enforce the above behavior. Should I use NoAction, ClientNoAction, Restrict or someting else?
You seem to be using EF Core 3.0 preview which adds more options not documented yet. But the option for classic cascade delete implemented at the database level has always been Cascade.
I haven't used WithMany() because that entity lacks references back to the interlinking entity.
In order to be able to fluently configure the relationship aspects, you have to fully specify the relationship parties by using the Has + With pair. Since navigation properties are not mandatory for either side of the relationship, all you need it to pass the correct argument to Has / With method - if you do have navigation property, pass the name or lambda expression accessor, otherwise don't pass anything (but still include the call). e.g.
entity.HasOne(e => e.Tag)
.WithMany() // <--
.OnDelete(DeleteBehavior.Cascade); // now you can do this
But note that DeleteBehavior.Cascade is the default for required relationships (in other words, when the FK is non nullable type), so you normally don't need fluent configuration for that. And if the property names follow the EF Core naming conventions, you don't need fluent configuration at all.
Simple example can be seen here.
I am a bit confused, about how to do relationships in EF Core 2.1. I been doing it the fluent way.
I have
public class Employee : IdentityUser
{
public int BranchId { get; set; }
public Branch Branch { get; set; }
}
public class Branch
{
public int Id { get; set; }
public int CompanyId { get; set; }
public Company Company { get; set; }
public ICollection<Employee> Employees { get; set; }
}
public class EmployeerConfig : IEntityTypeConfiguration<Employee>
{
public void Configure(EntityTypeBuilder<Employee> builder)
{
builder.ToTable("Employees");
}
}
public class BranchConfig : IEntityTypeConfiguration<Branch>
{
public void Configure(EntityTypeBuilder<Branch> builder)
{
builder.HasKey(x => x.Id);
builder.Property(x => x.Id).ValueGeneratedOnAdd();
builder.HasMany(x => x.Employees);
builder.ToTable("Branches");
}
}
All the examples I seen mostly to use dbcontext model builder, but that way is no longer needed as you can now use split it up as I done.
I done my relationships 2 ways first for Company and Branch I don't even specify the relationship yet went I build my db it knows, however when I try to do that with Employee and Branch the relationship was not formed.
This made me add builder.HasMany(x => x.Employees) in the branch config and now the relationship works, however I am not sure if I have specify something in the Employee area to make to complete?
I also don't know if I need to still add virtual to my collections anymore and why if I don't use ToTable() and build my db, all the table names are abbreviated, I thought that was automatic.
EmployeerConfig is fine you can add key if yoy want
For Branch Config add this line hope this'll help you.
builder.HasMany(x => x.Employee).WithOne(b => b.Branch).HasForeignKey(b => b.BranchId)
.OnDelete(DeleteBehavior.Cascade);
There seem to be multiple ways to do this. You can specify the relationship in EmployeeConfig.Configure or in BranchConfig.Configure, or in the DbContext's OnModelCreating method. I haven't tested to see what kind of behavior you get from specifying it in multiple places, but it's probably fine as long as it's consistent. However, in order to make maintenance easier, you probably want to specify it in only one place. I think the natural place is the DbContext, as this is a piece of information related to multiple entities, not just one. If you'd prefer to put it in one of the configuration files, I would suggest that putting it in the parent entity seems more natural.
Here is how you would specify it in EmployeeConfig.Configure:
builder.HasOne<Branch>(e => e.Branch).WithMany(b => b.Employees).HasForeignKey(e => e.BranchId);
That says that the Employee has one Branch, that the Branch has many Employees, and that the dependent entity (Employee) has a foreign key pointing back at the Branch, called BranchId.
Here is how you would specify it in BranchConfig.Configure:
builder.HasMany<Employee>(b => b.Employees).WithOne(e => e.Branch).HasForeignKey(e => e.BranchId);
Which says the same thing: the Branch has many Employees, each of which has one Branch, and that the dependent entity (Employee) has a foreign key called BranchId.
Here is how you would specify it in DbContext.OnModelCreating:
modelBuilder.Entity<Branch>().HasMany<Employee>(b => b.Employees).WithOne(e => e.Branch).HasForeignKey(e => e.BranchId);
or
modelBuilder.Entity<Employee>().HasOne<Branch>(e => e.Branch).WithMany(b => b.Employees).HasForeignKey(e => e.BranchId);
In my OnModelCreating method do I have to map every table's relationship like i did with my Tickets and Administrator class?
I read this article and the writer only did one of the relationships but not all of it. If you scroll down in the link I've provided to "Customize the Data Model by adding Code to the Database Context" you will see what I'm talking about.
Source: Click Here
IssueContext.cs
public class IssueContext : DbContext
{
public DbSet<User> Users { get; set; }
public DbSet<Ticket> Tickets { get; set; }
public DbSet<Category> Categories { get; set; }
public DbSet<Department> Departments { get; set; }
public DbSet<Administrator> Administrators { get; set; }
public DbSet<Depot> Depots { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Entity<Ticket>()
.HasMany(c => c.Administrators).WithMany(i => i.Tickets)
.Map(t => t.MapLeftKey("TicketID")
.MapRightKey("AdministratorID")
.ToTable("Adminstrators on Tickets"));
}
}
My Entity Diagram
In my OnModelCreating method do I have to map every table's relationship like i did with my Tickets and Administrator class?
EF Code First came with some default conventions like the one you already disable by calling this line of code:
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
Those conventions help EF Code First to know:
which entity belong to which table,
who is the primary key,
what is the relationship between your entities and create those relationship into your database tables
....
If you follow the conventions, you will not need to write a connfiguration by using fluent API or data annotation attributes.
The following configuration you worte:
modelBuilder.Entity<Ticket>()
.HasMany(c => c.Administrators).WithMany(i => i.Tickets)
.Map(t => t.MapLeftKey("TicketID")
.MapRightKey("AdministratorID")
.ToTable("Adminstrators on Tickets"));
is useful because if you let EF to generate the join table between Ticket and Administrator you will have some issue to know which is the left key and which is the right key. You also tell EF to generate TicketID and AdministratorID as column name instead of Ticket_ID and Administrator_ID which are the default names it will use on the join table.
To answer to your question. No you don't need to add mappings for all entities. Use conventions as much as possible and then use fluent configuration or data annotation attributes to tweak and refine some columns, tables etc like you do with your join table.
Side note: Adminstrators on Tickets is not a good table name for a table just use AdministratorsTickets
I have the following code first scenario:
public class crmContext : DbContext
{
public crmContext() : base("crmContext")
{
} // end crmContext()
public DbSet<Pool> Pools { get; set; }
public DbSet<Center> Centers { get; set; }
// Po DbSet PoolAssignments?
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Entity<Pool>()
.HasMany(c => c.Centers)
.WithMany(p => p.Pools)
.Map(
m =>
{
m.ToTable("PoolAssignments");
m.MapLeftKey("poolid");
m.MapRightKey("centerid");
});
} // end OnModelCreating()
} // class crmContext
The PoolAssignments table is created by modelBuilder and I would like to access it the same way I access Pools and Centers. For example:
crmContext db = new crmContext();
Pool pool db.Pools.Find(id);
PoolAssignment pa = db.PoolAssignments.Find(id);
The problem with this approach is that I have not defined PoolAssignment as a class and there is no DbSet PoolAssignments in crmContext. I think I am not understanding this part of Entity Framework very well.
If I define a PoolAssignment class (together with its navigation properties) and a PoolAssignments DbSet, then the modelBuilder code becomes unnecessary. Code first will generate the table for me.
I am simply trying to understand the logic behind using modelBuilder in such a scenario. How can I access the table PoolAssignments and how can I access data with the Entity Framework if I do not define classes? I have searched for an answer but I cannot find any. I have read many articles but none seems to cover this scenario.