Setting ForeignKey property with Fluent api and EntityBuilder<T> in c# - entity-framework

I have the following the poco class;
public class Trader : AuditableEntity
{
public int AccountManagerId { get; set; }
public ApplicationUser AccountManager { get; set; }
}
Where AccountManagerId is the foreign key to AccountManager.
When I then setup the data in EntityFrameworkCore is use the EntityTypeBuilder<T> to configure.
public override void Configure(EntityTypeBuilder<Trader> entity)
{
entity.HasKey(x => x.Id);
...
How using Fluent API can I state that AccountManager.HasForeignKey(AccountManagerId) please as I cannot see how to do this?
ApplicationUser has no reference to Trader, this is a one way relationship.

For 1-N relation:
entity.HasOne(x => x.AccountManager).WithMany().HasForeignKey(x => x.AccountManagerId);
For 1-1 relation:
entity.HasOne(x => x.AccountManager).WithOne().HasForignKey<Trader>(x => x.AccountManagerId);

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.

Could a foreign key property be a part of a composite primary key?

Following the TPC pattern.
I've one abstract class called Entity which is inherited by Person and LegalEntity.
public abstract class Entity
{
public int Id { get; set; }
}
public class LegalEntity : Entity
{
public string CorporateName { get; set;}
}
public class Person : Entity
{
public string Name { get; set; }
}
I've also another one called Agent which have many children. For simplification i'll show only one class Subscriber.
public abstract class Agent
{
public int EntityId { get; set; }
public int RoleId { get; set; }
}
public class Subscriber : Agent
{
public string Number { get; set; }
public Entity Entity { get; set; } // No EntityId here because the foreign key correspond to the Id of Subscriber
}
Below the configuration of my entities :
public AgentConfiguration()
{
HasKey(s => new { s.EntityId, s.RoleId });
...
}
public SubsbcriberConfiguration()
{
Map(m =>
{
m.MapInheritedProperties();
m.ToTable("T_ACTEUR_SOUSCRIPTEUR");
}
**.WithMany() //I don't want a property on the other side
.HasForeignKey(s => s.EntityId); // EF doesn't accept to put the property Id as a foreign key.**
}
public EntityConfiguration()
{
HasKey(e => e.Id);
Property(e => e.Id).HasColumnName("id_personne");
...
}
public PersonConfiguration()
{
Map(m =>
{
m.MapInheritedProperties();
m.ToTable("T_PERSONNE_PHYSIQUE");
});
}
I have a One to One relationship between the abstract class Entity and the concrete class Subscriber.
The primary key of the class Entity is at the same time a part of the composite primary key of the Subscriber and a foreign key.
Is it possible to configure this scenario?
When i declare the property Id as a foreign key, EF throws an exception like below :
The foreign key component 'EntityId' is not a declared property on type 'Subscriber'. Verify that it has not been explicitly excluded from the model and that it is a valid primitive property.
I tried many scenarios, but i didn't find a solution because i have a one to one relationship but the tables have different keys and the foreign key is a part of the composite primary key.
How can i configure a property as a foreign key and also a part of a composite primary key in code first?
What am I missing? Any help will be greatly appreciated!
Edit :
I broke up the inheritance of the class Agent and the TPC. Now the class Subscriber has no parent. when i configure it like below :
public SubsbcriberConfiguration()
{
HasKey(s => new { s.EntityId, s.RoleId });
Property(s => s.EntityId).HasColumnName("id_personne")
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
Property(s => s.RoleId).HasColumnName("id_role")
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
...
ToTable("T_ACTEUR_SOUSCRIPTEUR");
HasRequired(s => s.Entity)
.WithMany()
.HasForeignKey(s => s.EntityId)
.WillCascadeOnDelete(false);
}
Entity Framework is looking for another foreign key : column Extent1.Entity_Id does not exist
And the query generated by EF when i try to load a subscriber is :
`SELECT
"Extent1"."id_personne",
"Extent1"."id_role",
...
"Extent1"."Entity_Id"
FROM "T_ACTEUR_SOUSCRIPTEUR" AS "Extent1"
WHERE "Extent1"."id_personne" = ((73660)) AND
"Extent1"."id_role" = ((4))`
I don't know how to explain to EF that the foreign key property EntityId is the foreign key.
Could someone shed some light on this?
Thanks.
Well, I'm not sure if I understand your scenario, but this might be helpful.
Entities:
public class Entity
{
public int EntityId { get; set; }
}
public abstract class Agent
{
public int EntityId { get; set; }
public int RoleId { get; set; }
}
public class Subscriber : Agent
{
public string Number { get; set; }
public Entity Entity { get; set; }
}
Mapping:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Entity>()
.HasKey(e => e.EntityId);
//map the Subscriber, not the Agent
modelBuilder.Entity<Subscriber>()
.HasKey(a => new { a.EntityId, a.RoleId });
modelBuilder.Entity<Subscriber>()
.HasRequired(i => i.Entity)
.WithMany()
.HasForeignKey(i => i.EntityId)
.WillCascadeOnDelete(false);
base.OnModelCreating(modelBuilder);
}
Be aware that it is an "One-to-Many" relationship, not One-to-One. The article you posted on your comment uses UNIQUE CONSTRAINTS to "simulate" the 1:1 relationship in a 1:n relationship. I don't think it is a good approach.
However, let's suppose that you want to follow that way. Where would you put the UNIQUE CONSTRAINT? The FK is part of the composite PK. If you put an UNIQUE CONSTRAINT there, it would break the PK.
Considering that the PK is composed by two columns, and the FK is composed by 1 column of the PK, I don't see how a real 1:1 relationship can be possible. Because to have a 1:1 relationship, the FK column must be the same of PK column.
Hope it helps!

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.

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);

Specifying Foreign Key Entity Framework Code First, Fluent Api

I have a question about defining Foreign Key in EF Code First Fluent API.
I have a scenario like this:
Two class Person and Car. In my scenario Car can have assign Person or not (one or zero relationship).
Code:
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class Car
{
public int Id { get; set; }
public string Name { get; set; }
public Person Person { get; set; }
public int? PPPPP { get; set; }
}
class TestContext : DbContext
{
public DbSet<Person> Persons { get; set; }
public DbSet<Car> Cars { get; set; }
public TestContext(string connectionString) : base(connectionString)
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Car>()
.HasOptional(x => x.Person)
.WithMany()
.HasForeignKey(x => x.PPPPP)
.WillCascadeOnDelete(true);
base.OnModelCreating(modelBuilder);
}
}
In my sample I want to rename foreign key PersonId to PPPPP. In my mapping I say:
modelBuilder.Entity<Car>()
.HasOptional(x => x.Person)
.WithMany()
.HasForeignKey(x => x.PPPPP)
.WillCascadeOnDelete(true);
But my relationship is one to zero and I'm afraid I do mistake using WithMany method, but EF generate database with proper mappings, and everything works well.
Please say if I'm wrong in my Fluent API code or it's good way to do like now is done.
Thanks for help.
I do not see a problem with the use of fluent API here. If you do not want the collection navigational property(ie: Cars) on the Person class you can use the argument less WithMany method.