I have 2 entities Role and Permission with association one-to-many accordingly.
public class Role
{
public int Id { get; set; }
public bool IsAdmin { get; set; }
public virtual ICollection<Permission> Permissions { get; set; }
}
public class Permission
{
public int Id { get; set; }
public string Code { get; set; }
public string GroupName { get; set; }
public virtual Role Role { get; set; }
}
And created mapping classes for them inherited from EntityTypeConfiguration class.
When I run my application EF created database for me and foreign key for these entities above was Role_Id.
How can I change existing or add new convention to get ride of the underscore in foreign key?
So I want to have RoleId as a foreign key for my entities.
I don't want use data annotation attributes and don't want to add extra property to Permission class (public int RoleId { get; set; }) in order to use it in mapping like this:
HasRequired(x => x.Role).WithMany(y => y.Permissions).HasForeignKey(o => o.RoleId);
Thanks,
Alexey
Entity framework currently doesn't support custom global conventions but you can overwrite the name of the key in fluen API:
modelBuilder.Entity<Permission>()
.HasRequired(x => x.Role)
.WithMany(y => y.Permissions)
.Map(m => m.MapKey("RoleId"));
Related
I've created a table that has a relation with itself the table has a one-to-many relationship here is my Entity:
public class Permission
{
[Key]
public int PermissionId { get; set; }
public string PermissionTitle { get; set; }
public int? ParentId { get; set; }
#region Relations
[ForeignKey("ParentId")]
public virtual ICollection<Permission> Permissions { get; set; }
#endregion
}
but when I used migration to create the table in SQL, update-database failed for this error:
Introducing FOREIGN KEY constraint 'FK_Permission_Permission_ParentId' on table 'Permission' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
So I decided to use fluent API to solve this issue but I don't know how to Specify ON DELETE NO ACTION by Fluent API on a table that has a relation with itself. any help?
is there any solution to solve my problem?
For EF Core the Entity should normally have two Navigation Properties, like this:
public class Permission
{
[Key]
public int PermissionId { get; set; }
public string PermissionTitle { get; set; }
public int? ParentPermissionId { get; set; }
#region Relationships
public virtual Permission ParentPermission { get; set; }
public virtual ICollection<Permission> ChildPermissions { get; } = new HashSet<Permission>();
#endregion
}
And configured like this:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Permission>()
.HasMany(p => p.ChildPermissions)
.WithOne(p => p.ParentPermission)
.HasForeignKey(p => p.ParentPermissionId)
.OnDelete(DeleteBehavior.Restrict);
base.OnModelCreating(modelBuilder);
}
Is it possible to configure one to one relationship using fluent api on database which does not meet convention requirements?
Below I give you sample of database and generated models.
Be aware of that tables do not define any constraints and indices except primary keys.
Tables:
create table Person (
PersonKey int primary key
)
create table Address (
AddressKey int primary key,
owner int not null // normally should be foreign key to Person
)
Code first models generated from db:
public partial class Person
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int PersonKey { get; set; }
}
public partial class Address
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int AddressKey { get; set; }
public int Owner { get; set; }
}
To be able to navigate from Address to Person, navigation property was added to Address class:
public partial class Address
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int AddressKey { get; set; }
public int Owner { get; set; }
public virtual Person Person { get; set; }
}
If program tries execute this query:
var Addresss = context.Addresss.Include(x => x.Person).ToList();
runtime raises exception: "Invalid column name 'Person_PersonKey'". Because context do not configure any custom mappings it tries to find foreign key by convention but Owner property does not meet convention requirements, hence the exception. So there is a need to add mappings.
If relationship between Person and Address would be one to many we could add such a configuration:
modelBuilder.Entity<Address>()
.HasOptional(x => x.Person)
.WithMany()
.HasForeignKey(x => x.Owner);
and query defined above would execute correctly. But what if Person class would have navigation property to Address so we would have bidirectional one to one relation:
public partial class Person
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int PersonKey { get; set; }
public virtual Address Address { get; set; }
}
So above configuration will not work and my question is, is it possible to configure it without changing db and property names and if yes what configuration needs to be applied using only fluent api?
Here is my suggested code, I hope I understand you correctly!
public partial class Person
{
public int PersonKey { get; set; }
public Address Address {get;set;}
}
public partial class Address
{
public virtual Person Person { get; set; }
public int PersonId { get; set; }
public string AddressInfo {get;set;}
}
modelBuilder.Entity<Person>()
.HasKey(a => a.PersonKey);
modelBuilder.Entity<Course>()
.Property(c => c.CourseId)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
modelBuilder.Entity<Address>()
.HasKey(a => a.PersonId);
modelBuilder.Entity<Person>()
.HasRequired(p => p.Address)
.WithRequiredPrincipal(a => a.PersonId);
I have 2 entities:
public class User
{
public int userId { get; set; }
public string name { get; set; }
public Guid userGuid { get; set; }
}
public class Absence
{
public int absenceId { get; set; }
public Guid applicantId { get; set; }
public User applicant { get; set; }
public Guid permitterId{ get; set; }
public User permitter{ get; set; }
...
}
AbsencesConfiguration:
this.HasRequired(u => u.Applicant).WithMany().HasForeignKey(d => d.ApplicantId);
this.HasRequired(u => u.Permitter).WithMany().HasForeignKey(d => d.PermitterId);
I'd like a Fluent API mapping between the two classes, but it gives this error message:
Blockquote\tSystem.Data.Entity.Edm.EdmAssociationConstraint: : The types of all properties in the Dependent Role of a referential constraint must be the same as the corresponding property types in the Principal Role. The type of property 'ApplicantId' on entity 'Absences' does not match the type of property 'UserId' on entity 'User' in the referential constraint 'Absences_Applicant'.
I think this is because EF try to join the two tables with the UserId of the User entity and not with UserGuid column. I thought I would make these two columns of Absence entity unique, but how I can map them together?
Thanks in advance.
The problem is your User primary key is an int, but your foreign key is a Guid.
You need to alter either your User class to have a guid for userId:
public Guid userId { get; set; }
or, update your Absence class to use an int:
public int applicantId { get; set; }
I have following classes
public class Employer
{
[Key]
public Int64 EmployerID { get; set; }
public String CompanyName { get; set; }
public virtual List<Employee> Employees { get; set; }
}
public class Employee
{
[Key]
public Int64 EmployeeID { get; set; }
public String EmployeeName { get; set; }
public virtual Employer EmployerInfo { get; set; }
}
In the Database context I have set the relation as
modelBuilder.Entity<Employer>()
.HasMany(p => p.Employees)
.WithRequired()
.Map(x => x.MapKey("EmployerID"));
After executing some actions, database gets created with Employee table having EmployerID as foreign key and one extra key EmployerInfo_EmployerID.
Now when I fetch employer data, I am getting employee details with it.
But when I tried to fetch employee data I am getting EmployerInfo as null. This is because I need relationship from Employee to EmployerInfo.
How do I set the bi-directional relationship in this context?
You need to update your fluent so your relationship mapping contains both ends:
modelBuilder.Entity<Employer>()
.HasMany(p => p.Employees)
.WithRequired(e => e.EmployerInfo)
.Map(x => x.MapKey("EmployerID"));
I have a sample code:
public class Tag
{
public int TagId { get; set; }
public virtual ICollection<User> Users { get; set; }
}
public class User
{
public int UserId { get; set; }
public virtual ICollection<Tag> Tags { get; set; }
}
When I run EF over my model (i use code first approach), i get some tables automatically created in my db:
Users
Tags
UserTagUsers <-- junction table for many-to-many relationship
It is okay, till I decide to add one more property to User entity:
public class User
{
public int UserId { get; set; }
public virtual ICollection<Tag> Tags { get; set; }
public virtual ICollection<Tag> Tags2 { get; set; }
}
in this case EF generates completely different relations, it removes UserTagUsers junction table, but adds some additional properties to Tags table in order to make it one-to-one mapping.
How can I explicitly tell EF to make the property Tags and Tags2 to be many-to-many?
Use fluent API to configure the mappings
modelBuilder.Entity<User>()
.HasMany(u => u.Tags).WithMany(t => t.Users)
.Map(m =>
{
m.ToTable("UserTags");
m.MapLeftKey("UserId");
m.MapRightKey("TagId");
});
modelBuilder.Entity<User>()
.HasMany(u => u.Tags2).WithMany(t => t.Users2)
.Map(m =>
{
m.ToTable("UserTags2");
m.MapLeftKey("UserId");
m.MapRightKey("TagId");
});