Entity Framework Many to Many Database Migration - entity-framework

I am building ASP MVC web site using Entity Framework 4.4 with .NET Framework 4.0
I've add to my model a many to many relation like so:
public class User {
public int UserID { get; set; }
public string Username { get; set; }
public virtual ICollection<Tenant> Tenants { get; set; }
}
public class Tenant {
public string TenantID { get; set; }
public string Name { get; set; }
public virtual ICollection<User> Users { get; set; }
}
When I run Add-Migration command I get this migration class (I remove the Down method)
public partial class TenantUsersManyToManyMigration : DbMigration
{
public override void Up()
{
CreateTable(
"dbo.UserTenants",
c => new
{
User_UserID = c.Int(nullable: false),
Tenant_TenantID = c.String(nullable: false, maxLength: 128),
})
.PrimaryKey(t => new { t.User_UserID, t.Tenant_TenantID })
.ForeignKey("dbo.Users", t => t.User_UserID, cascadeDelete: true)
.ForeignKey("dbo.Tenants", t => t.Tenant_TenantID, cascadeDelete: true)
.Index(t => t.User_UserID)
.Index(t => t.Tenant_TenantID);
}
}
Why are the field names for TenantID and UserID are User_UserID and Tenant_TenantID and not UserID and TenantID, respectively.
How can I change the default migration scaffolding (or my model) to make cascadeDelete to be false? (currently I simply change it by hand).

You can create your mapping table the way you're wanting using fluent notation. In your DbContext class, override the OnModelCreating with this:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.HasMany(u => u.Tenants)
.WithMany(t => t.Users)
.Map(m =>
{
m.ToTable("UserTenants");
m.MapLeftKey("UserId");
m.MapRightKey("TenantId");
});
}
Also, using fluent, if you want to disable cascade deleting on individual tables, you can use the .WillCascadeDelete(false) when mapping properties. Here's a great post on MSDN on how to use fluent notations.

You can remove the cascade delete convention this way:
using System.Data.Entity.ModelConfiguration.Conventions;
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
}
And then see if the scaffolding changes. I've personally never used it.
Also, Microsoft (kind of) explains the FK naming conventions in this link under the header Foreign Keys.

Related

ASP.NET Core Identity Added extra foreign key in AspNetUserRoles

There are two extra foreign keys (TheUsrId, TheRoleId) in AspNetUserRoles table as you can see in the picture below.
And here is the configuration:
public class AppUser : IdentityUser<int>
{
... // other properties
public ICollection<AppUserRole> TheUserRolesList { get; set; }
}
public class AppRole : IdentityRole<int>
{
public ICollection<AppUserRole> TheUserRolesList { get; set; }
}
public class AppUserRole : IdentityUserRole<int>
{
public AppUser TheUser { get; set; }
public AppRole TheRole { get; set; }
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<AppUser>(b =>
{
b.HasMany(x => x.TheUserRolesList)
.WithOne(x => x.TheUser)
.HasForeignKey(x => x.UserId)
.IsRequired();
});
modelBuilder.Entity<AppRole>(b =>
{
b.HasMany(e => e.UserRoles)
.WithOne(e => e.Role)
.HasForeignKey(ur => ur.RoleId)
.IsRequired();
});
base.OnModelCreating(modelBuilder);
}
I've tried several ways such as this and changed the name of TheUser to User but Eventually, I had UserId1 as a foreign key.
ASP.NET Core Identity creates its own relationships and columns by itself in AppRole and AppUserRole when you don't write anything in those classes.
In AppUserRole , when you create TheUser and TheRole properties, entity framework adds "Id" at the end of it and creates a new relationship. So this is the rule of entity framework.
You should remove them all and try to see the reason why.
Finally, I noticed that it was a bug in EntityFrameworkCore version 5.0.4 and After Updating to 5.0.17 the problem was solved.

entity framework one to one with foreign key

It seems that Entity Framework have some conventions to deal with one to one relationship.
I'm using Fluent API and I need my child entity to have PK and Also FK.
Is it possible without using the [ForeignKey] attribute?
Consider the following example:
public class Principal
{
public int Id { get; set; }
public Dependent Dependent { get; set; }
}
public class Dependent
{
public int Id { get; set; }
public Principal Principal { get; set; }
}
To configure Dependent's Id property to be a foreign key to Principal's Id property with Fluent API you may choose one of the following options:
1) Starting with Entity<Dependent>:
public class AppDbContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Dependent>().HasRequired(d => d.Principal).WithOptional(p => p.Dependent);
}
}
2) Starting with Entity<Principal>
public class AppDbContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Principal>().HasOptional(p => p.Dependent).WithRequired(d => d.Principal);
}
}
They both will result in the following code first migration:
CreateTable(
"dbo.Principals",
c => new
{
Id = c.Int(nullable: false, identity: true),
})
.PrimaryKey(t => t.Id);
CreateTable(
"dbo.Dependents",
c => new
{
Id = c.Int(nullable: false),
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.Principals", t => t.Id)
.Index(t => t.Id);
where Dependent's Id property is configured to be as a PK and a FK to Principal's Id property.

Map Existing Entity with Existing Table in Entity FrameWork

Is it possible to map existing tables with existing Entities in Entity frame work as like NHibernate doing.
For example. I have entity as
public class User
{
public Int64 userId { set; get; }
public String Username { set; get; }
public Int64 RoleId { set; get; }
}
public class Role
{
public Int64 roleId { set; get; }
public String roleName { set; get; }
public IList<User> listUser { set; get; }
}
I have Table as
Users with id,name,roleId
Roles with id,name.
Now I want to map both using XML files. Is it possible to map exiting tables with exiting Entities.
You have a few options:
1) Manage your mapping via the database first edmx file (see http://www.asp.net/mvc/tutorials/mvc-5/database-first-development/creating-the-web-application)
2) Start with the database first approach then move over to a code first like approach using the fluent api (see http://agilenet.wordpress.com/2011/04/11/entity-framework-4-1-rc-with-an-existing-database/)
Usual way of mapping in EF is data annotation attributes or fluent mapping (actually with NHibernate fluent mapping is also better, because it gives you compile-time checks). So, here is fluent mapping for your classes:
public class UserMapping : EntityTypeConfiguration<User>
{
public UserMapping()
{
ToTable("Users"); // Not necessary, EF will use this mapping by default
HasKey(u => u.userId);
Property(u => u.userId).HasColumnName("id");
Property(u => u.Username).HasColumnName("name");
Property(u => u.RoleId).HasColumnName("roleId");
}
}
public class RoleMapping : EntityTypeConfiguration<Role>
{
public RoleMapping()
{
ToTable("Roles"); // Not necessary, EF will use this mapping by default
HasKey(r => r.roleId);
Property(r => r.roleId).HasColumnName("id");
Property(r => r.roleName).HasColumnName("name");
HasMany(r => r.listUser)
.WithRequired()
.HasForeignKey(u => u.RoleId);
}
}
Just provide these mappings to your DbContext:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new UserMapping());
modelBuilder.Configurations.Add(new RoleMapping());
base.OnModelCreating(modelBuilder);
}
I suggest you to read MSDN article Configuring/Mapping Properties and Types with the Fluent API.
Side note - another article to read is Naming Guidelines, especially its Capitalization Styles part.

Prevent Entity Framework from adding duplicated keys in migration with table per type inheritance

I have a simple model using table per type inheritance for some entities. The problem is that when I generate the migration using Add-Migration, It creates a duplicated index on the child class' primary key.
Class definitions:
class Product
{
[Key]
public int ProductId { get; set; }
public int Value { get; set; }
}
class Service : Product
{
public int OtherValue { get; set; }
}
And in my context, I specify the table names for both classes
class ProductContext : DbContext
{
virtual public DbSet<Product> ProductSet { get; set; }
virtual public DbSet<Service> ServiceSet { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Product>().ToTable("Product");
modelBuilder.Entity<Service>().ToTable("Service");
}
}
Running Add-Migration results in the following:
public override void Up()
{
CreateTable(
"dbo.Product",
c => new
{
ProductId = c.Int(nullable: false, identity: true),
Value = c.Int(nullable: false),
})
.PrimaryKey(t => t.ProductId);
CreateTable(
"dbo.Service",
c => new
{
ProductId = c.Int(nullable: false),
OtherValue = c.Int(nullable: false),
})
.PrimaryKey(t => t.ProductId)
.ForeignKey("dbo.Product", t => t.ProductId)
.Index(t => t.ProductId);
}
It creates an additional index on Service.ProductId when it's already the primary key. Is there some annotation I am missing in order to prevent the index from being added?
Tested with both EF5 and EF6 with the same results.
Just for whom (still) facing this problem, as I understand it's a bug fixed in version 6.1.1 of EF (https://entityframework.codeplex.com/workitem/1035).
So just updating to the latest version of EF should fix it. But if you couldn't or wouldn't update, the workaround is just as simple as deleting duplicate Index in generated migration file and save (don't also forget to disable AutomaticMigrationsEnabled if enabled).
I suspect that the Entity Framework adds an index to foreign keys - even when the foreign key is already indexed because it is also the primary key. Maybe it's an oversight or maybe it's a low priority for the framework developers. Either way, you can adjust the Up() method yourself. See item 7 on this useful blog Tips for Entity Framework Migrations
Try making both tables inherit from an abstract class as described here
public abstract class ProductBase
{
[Key]
public int ProductId { get; set; }
}
public class Product: ProductBase
{
public int Value { get; set; }
}
public class Service : ProductBase
{
public int OtherValue { get; set; }
}

Entity Framework Code First - Navigation property on Composite Primaty Key

Firebird 2.5
Entity Framework 5
FirebirdClientDll 3.0.0.0
Hi, I'm trying to access my legacy database with the Entity Framework (Code First).
I got the problem that the database does not use foreign keys...
public class CUSTOMERS
{
public int CUSTOMERID { get; set; }
public string NAME{ get; set; }
}
public class INVOICES
{
public int INVOICEID{ get; set; }
public int CUSTOMERID{ get; set; }
public virtual CUSTOMERS CUSTOMERS { get; set; }
}
public class INVOICEContext : DbContext
{
public DbSet<CUSTOMERS> CUSTOMERS{ get; set; }
public DbSet<INVOICES> INVOICES{ get; set; }
public INVOICEContext(DbConnection connectionString) : base(connectionString, false)
{
Database.SetInitializer<INVOICEContext>(null);
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
/*modelBuilder.Entity<INVOICES>().HasRequired(b => b.CUSTOMERS)
.WithMany()
.Map(p => p.MapKey("INVOICEID"));*/ //Doesn't work because INVOICEID is defined
modelBuilder.Entity<INVOICES>().HasKey(a => new { a.INVOICEID, a.CUSTOMERID});
modelBuilder.Entity<CUSTOMERS>().HasKey(a => new { a.CUSTOMERID });
base.OnModelCreating(modelBuilder);
}
}
Normally I could remove the property CUSTOMERID from the class INVOICES, but in this case it is part of the primary key...
I found many threads which suggested to use IsIndependent, but it seems to be removed from the Entity Framework 5 (or 4.1).
I hope you can understand my poor English and maybe give me a hint what I'm doing wrong ^^
I don't know what you mean with "the database does not use foreign keys". So, maybe the following is not the answer you are looking for. But I'd say that you can use your relationship mapping that is commented out in your code if you replace ...MapKey... by HasForeignKey and use CUSTOMERID instead of INVOICEID as the foreign key property:
modelBuilder.Entity<INVOICES>()
.HasRequired(b => b.CUSTOMERS)
.WithMany()
.HasForeignKey(b => b.CUSTOMERID);
The model and the rest of the mapping is fine in my opinion. Your relationship is an identifying relationship (that means that the foreign key is part of a composite primary key) which is a valid mapping with Entity Framework.
Try this ...
modelBuilder.Entity<INVOICES>()
.HasRequired(i => i.CUSTOMERS)
.WithMany()
.HasForeignKey(i => i.CUSTOMERID);