In my project I have following DomainModel.
public class Login
{
public Guid Id { get; set; }
public Login CreatedBy {get; set; }
}
I am using fluent configuration as below:
modelBuilder.Entity<Login>()
.HasKey(x => x.Id)
.ToTable("Login");
modelBuilder.Entity<Login>()
.HasOptional(x => x.CreatedBy)
.WithMany()
.HasForeignKey(x => x.CreatedBy);
My code in repository to get all Logins data is as below:
return from d in Db.Logins.Include("CreatedBy")
select d;
When I execute the code I am getting following error:
The foreign key component 'CreatedBy' is not a declared property on type 'Login'. Verify that it has not been explicitly excluded from the model and that it is a valid primitive property.
Can anyone suggest what I am doing wrong here?
Thanks in advance
.. has not been explicitly excluded from the model and that it is a
valid primitive property
Your foreign key mapping .HasForeignKey(x => x.CreatedBy) does not use a primitive property.
public class Login
{
public Guid Id { get; set; }
public virtual Login CreatedBy {get; set; }
}
Then map it like
modelBuilder.Entity<Login>()
.HasKey(x => x.Id)
.ToTable("Login");
modelBuilder.Entity<Login>()
.HasOptional(x => x.CreatedBy)
.WithMany()
.Map(x => x.MapKey("ForeignKeyColumn"));
Related
I want to create a 1-0..1 relation between a table and a temporal table using EF Core code-first approach. But when I add the migration I get the error :
Navigation 'Ticket (Dictionary<string, object>).TicketAdministration' was not found. Please add the navigation to the entity type before configuring it.
I let you see step by step what I am doing:
I create the Ticket and TicketAdministration classes:
public partial class Ticket
{
public long Id { get; set; }
//... other unuseful props
public virtual TicketAdministration TicketAdministration { get; set; }
}
public class TicketAdministration
{
public long Id { get; set; }
//... other unuseful props
public long? TicketId { get; set; }
public virtual Ticket Ticket { get; set; }
}
Then I configured the two classes/tables:
modelBuilder.Entity<Ticket>(entity =>
{
entity.ToTable("tickets");
entity.Property(e => e.Id)
.HasColumnType("bigint")
.ValueGeneratedOnAdd();
});
modelBuilder.Entity<TicketAdministration>(entity =>
{
entity.ToTable("ticket_admininistration", "admin", t => t.IsTemporal());
entity.HasKey(e => e.Id);
entity.Property(e => e.Id).UseIdentityColumn(1, 1);
entity.HasOne(d => d.Ticket)
.WithOne(p => p.TicketAdministration)
.HasForeignKey<TicketAdministration>(b => b.TicketId)
.OnDelete(DeleteBehavior.ClientCascade)
.HasConstraintName("FK_dbo.Tickets_admin.TicketAdministration_TicketId");
});
How do I have to configure the relationship? Why is it expecting a dictionary? What the dictionary represent?
Thank you
I want to create a contact list in my application. I therefore created a mapping table between ApplicationUsers:
public class UserContacts
{
public string UserId { get; set; }
public virtual ApplicationUser User { get; set; }
public string ContactId { get; set; }
public virtual ApplicationUser Contact { get; set; }
}
And then registered the relations between my ApplicationUser and this table:
builder.Entity<UserContacts>()
.HasOne(p => p.Contact)
.WithMany(p => p.Contacts)
.HasForeignKey(p => p.ContactId);
builder.Entity<UserContacts>()
.HasOne(p => p.User)
.WithMany(p => p.Contacts)
.HasForeignKey(p => p.UserId);
And added a property in my ApplicationUser class:
public virtual ICollection<UserContacts> Contacts { get; set; }
But whenever I try to update the database I get the following error:
Cannot create a relationship between 'ApplicationUser.Contacts' and 'UserContacts.User', because there already is a relationship between 'ApplicationUser.Contacts' and 'UserContacts.Contact'. Navigation properties can only participate in a single relationship.
Can you please explain to me what I am missing?
Thanks.
You need to add another collection to ApplicationUser:
public virtual ICollection<UserContacts> **Users** { get; set; }
Then change the fluent code to point there (they can't point to same collection):
builder.Entity<UserContacts>()
.HasOne(p => p.User)
.WithMany(p => **p.Users**)
.HasForeignKey(p => p.UserId);
I have a Mentorship entity, which has Student and Mentor as FKs:
[Required]
public int MentorId { get; set; }
public virtual User Mentor { get; set; }
[Required]
public int StudentId { get; set; }
public virtual User Student { get; set; }
User model:
public virtual ICollection<Mentorship> Mentorships { get; set; }
Fluent API:
modelBuilder.Entity<Mentorship>()
.HasRequired(c => c.Mentor)
.WithMany()
.HasForeignKey(u => u.MentorId);
modelBuilder.Entity<Mentorship>()
.HasRequired(c => c.Student)
.WithMany()
.HasForeignKey(u => u.StudentId);
In my database, I see StudentId and MentorId columns which have been populated correctly, but I also see a User_UserId column that is not being used by anything. What have I done wrong?
You have used the WithMany() overload that configures the relationship to be required:many without a navigation property on the other side of the relationship - but you do have a navigation property on the other side of the relationship.
Try this:
modelBuilder.Entity<Mentorship>()
.HasRequired(c => c.Mentor)
.WithMany(d => d.Mentorships)
.HasForeignKey(u => u.MentorId);
modelBuilder.Entity<Mentorship>()
.HasRequired(c => c.Student)
.WithMany(d => d.Mentorships)
.HasForeignKey(u => u.StudentId);//oops! just realised that we just
//specified that Mentorships is using MentorId
//as the FK
References:
Required WithMany Method
Why do I get an extra foreign key?
Edit
Scratch that. Just realised you are trying to create two relationships with only one navigation property on the many side. You can't have a navigation property with 2 foreign keys. You need to introduce inheritance on the User side or remove the Mentorships navigation property from the User class or introduce separate StudentMentorships and MentorMentorships navigation properties
Edit 2
Finding a user once you've defined separate navigation properties
int userId = 123;//the one we want to find
var user = Users.Where(x => x.StudentMentorships.Any(s => s.StudentID == userId)
|| x.MentorMentorships.Any(s => s.MentorID == userId);
Here's my POCO
public class Game
{
public Guid Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Galaxy> Galaxies { get; set; }
}
Here's the TypeConfiguration ....
public class GameConfiguration : EntityTypeConfiguration<Game>
{
public GameConfiguration()
{
HasKey(x => x.Id);
Property(x => x.Id).HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity);
HasMany(x => x.Galaxies);
Property(x => x.Name)
.IsRequired()
.HasMaxLength(50);
}
}
My question is this... why, when this is added as a migration does the migration code not set the "Name" property as a "NOT NULL"? It also ignores the MaxLength setting too. Why is this?
CreateTable(
"dbo.Games",
c => new
{
Id = c.Guid(nullable: false),
Name = c.String(),
})
.PrimaryKey(t => t.Id);
At first glance the rest of your configuration matches what would happen by convention even if the configuration constructor never ran and the if the name property is missing that could explain it. The code that registers the configuration in the model builder is missing.
You can register the entity configuration, e.g. inside the OnModelCreated method like this:
modelBuilder.Configurations.Add(new GameConfiguration());
I have the following property declarations and mappings (abridged classes):
public class Consumer: AuditableEntity
{
public virtual Consumer Parent { get; set; }
public virtual User User { get; set; }
public virtual Role Role { get; set; }
public virtual ICollection<Consumer> Consumers { get; set; }
}
public ConsumerMap()
{
HasRequired(t => t.Role)
.WithMany(t => t.Consumers)
.Map(a => a.MapKey("RoleId"))
.WillCascadeOnDelete(false);
HasRequired(t => t.User)
.WithOptional(t => t.Consumer)
.Map(a => a.MapKey("UserId"))
.WillCascadeOnDelete(false);
}
A manual database query confirms all joins are successful and in fact, a manual execution of the query sent by EF is successful. Yet when I use the following query, the User property on the two Consumer objects returned is null:
return CurrentDbContext.Consumers.Include("User").Include("Role").Where(e => !e.IsDeleted);