Lookup table with EF Codefirst - entity-framework

I would like to create Resource and RelatedResources table with EF Code First as below:
Table Resource
int Id
string ResourceName
int Category
Table RelatedResource
int ResourceId
int RelatedResourceId
I tried as below but
Error: The ForeignKeyAttribute on property 'ResourceId' on type 'Models.ResourceRelated' is not valid. The navigation property 'Resource' was not found on the dependent type 'Models.ResourceRelated'. The Name value should be a valid navigation property name.
public class ResourceRelated
{
[ForeignKey("Resource")]
public int ResourceId { get; set; }
public virtual Resource Resoure { get; set; }
public virtual ICollection<Resource> RelatedResource { get; set; }
}
Kindly Advice!

If you want RelatedResource table, than you want many-to-many relationship. You can achieve this in next way
public class Resource
{
public int ResourceId { get; set; }
public string ResourceName { get; set; }
public int Category { get; set; }
[InverseProperty("Resoure")]
public virtual ICollection<RelatedResource> RelatedResource { get; set; }
[InverseProperty("ResourceRelated")]
public virtual ICollection<RelatedResource> ResourceRelated { get; set; }
}
public class RelatedResource
{
[Key]
[Column(Order = 1)]
[ForeignKey("Resoure")]
public int ResourceId { get; set; }
[Key]
[Column(Order = 2)]
[ForeignKey("ResourceRelated")]
public int ResourceRelatedId { get; set; }
public virtual Resource Resoure { get; set; }
public virtual Resource ResourceRelated { get; set; }
}
If you prefer do not work with RelatedResource in code, than you can do next
public class Resource
{
public int ResourceId { get; set; }
public string ResourceName { get; set; }
public int Category { get; set; }
public virtual ICollection<Resource> RelatedResource { get; set; }
public virtual ICollection<Resource> ResourceRelated { get; set; }
}
After you need next additional configuration
internal class ResourceConfiguration : EntityTypeConfiguration<Resource>
{
public ResourceConfiguration()
{
HasMany(s => s.ResourceRelated).WithMany(c => c.RelatedResource)
.Map(cs => {
cs.MapLeftKey("ResourceId");
cs.MapRightKey("RelatedResourceId");
cs.ToTable("RelatedResource"); }
);
}
}
And finally add this configuration
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
///other configuration code
modelBuilder.Configurations.Add(new ResourceConfiguration());
}
But if you want to have "resource tree" than you do not need RelatedResource table
public class Resource
{
public int ResourceId { get; set; }
public string ResourceName { get; set; }
public int Category { get; set; }
public int? ResourceRelatedId { get; set; }
public Resource ResourceRelated { get; set; }
[ForeignKey("ResourceRelatedId")]
public virtual ICollection<Resource> RelatedResource { get; set; }
}

Related

EF Core 7 - error occurred: the entity type 'List<string>' requires a primary key to be defined

I get an error when I use EF Core 7 to create entities.
The entity type 'List' requires a primary key to be defined. If you intended to use a keyless entity type, call 'HasNoKey' in 'OnModelCreating'. For more information on keyless entity types, see https://go.microsoft.com/fwlink/?linkid=2141943.
I have found the error prop, that's Project of service entity, when I only annotate Project of service entity, then I can run Add-Migration successfully. I don't know why and I also don't know how to fix this error.
Does somebody know this error? Please help...
public class Service : EntityBase
{
public Guid? DefaultCapacityUnitId { get; set; }
public Guid? DefaultSizeUnitId { get; set; }
public virtual SizeUnit DefaultSizeUnit { get; set; }
public Guid ProjectId { get; set; }
public Project Project { get; set; }
public Guid? ParentId { get; set; }
public virtual Service Parent { get; set; }
public Guid DisciplineId { get; set; }
public virtual Discipline Discipline { get; set; }
public virtual List<Service> SubServices { get; set; } = new List<Service>();
}
public class Equipment : EntityBase
{
public Guid ProjectId { get; set; }
public Project Project { get; set; }
public Guid? ServiceId { get; set; }
public virtual Service Service { get; set; }
public Guid DisciplineId { get; set; }
public virtual Discipline Discipline { get; set; }
}
public abstract class EntityBase
{
[Key]
public virtual Guid Id { get; set; } = Guid.NewGuid();
private string name;
[Required, MaxLength(200)]
public virtual string Name
{
get
{
return name?.Trim();
}
set
{
name = value?.Trim();
}
}
private string shortName;
[Required, MaxLength(100)]
public virtual string ShortName
{
get
{
return shortName?.Trim();
}
set
{
shortName = value?.Trim();
}
}
[NotMapped]
public EntityBase Snapshot { get; set; }
[NotMapped]
public List<string> ValueChangedProperties { get; set; } = new List<string>();
}
public class Project : EntityBase
{
}
public class Discipline : EntityBase
{
public Guid ProjectId { get; set; }
public virtual Project Project { get; set; }
public virtual List<Service> Services { get; set; } = new List<Service>();
public Guid? ScenarioId { get; set; }
public Guid? ParentId { get; set; }
public virtual Discipline Parent { get; set; }
}
public partial class TestDbContext : DbContext
{
public TestDbContext(DbContextOptions<TestDbContext> options)
: base(options)
{ }
public TestDbContext()
{
}
public DbSet<Project> Projects { get; set; }
public DbSet<Discipline> Disciplines { get; set; }
public DbSet<Service> Services { get; set; }
public DbSet<ServiceGroup> ServiceGroups { get; set; }
public DbSet<SizeUnit> SizeUnits { get; set; }
public DbSet<Equipment> Equipments { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
var entityTypes = typeof(TestDbContext).GetProperties()
.Where(p => p.PropertyType.IsGenericType && p.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>))
.Select(p => p.PropertyType.GetGenericArguments()[0]).ToList();
entityTypes.ForEach(entityType => {
var entityName = entityType.Name;
modelBuilder.Entity(entityType).ToTable(entityName);
});
modelBuilder.Entity<ServiceMapping>().HasOne(x => x.Service).WithMany().HasForeignKey(x => x.ServiceId).OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<ServiceMapping>().HasOne(x => x.TargetService).WithMany().HasForeignKey(x => x.TargetServiceId).OnDelete(DeleteBehavior.Cascade);
base.OnModelCreating(modelBuilder);
}
}
public class ServiceGroup : EntityBase
{
public Guid ProjectId { get; set; }
public virtual Project Project { get; set; }
public Guid? ScenarioId { get; set; }
}
public class ServiceMapping : EntityBase
{
public Guid ProjectId { get; set; }
public virtual Project Project { get; set; }
public Guid ServiceId { get; set; }
public virtual Service Service { get; set; }
public Guid TargetServiceId { get; set; }
public virtual Service TargetService { get; set; }
}
public class SizeUnit : EntityBase
{
public Guid ProjectId { get; set; }
public virtual Project Project { get; set; }
public int UnitType { get; set; }
}
If I annotate Project of service entity, then it's all right.

EF code first model not in sync with database

My EF Code First model for some reason is not in sync with the db. I'm getting this error:
{"Invalid column name 'Type_Id1'."}
The field is actually called 'Type_Id' so I'm not sure from where that 1 comes up. I have the table column called as Type_Id and also I've added a Type_Id in my type entity model.
Why might I be getting that error message, plus why I'm getting 1 at the end of the name?
Update
My Task class:
public class Task
{
public Task()
{
Language = 1;
Grades = new HashSet<Grade>();
Categories = new HashSet<Category>();
Subjects = new HashSet<Subject>();
Rooms = new Collection<Room>();
Tools = new Collection<Tool>();
}
[Key]
public int Id { get; set; }
public string Description { get; set; }
public virtual TaskType Type { get; set; }
public string Rules { get; set; }
[Required]
[StringLength(200), MinLength(1)]
public string Name { get; set; }
public int PreperationTime { get; set; }
public int InstructionTime { get; set; }
public int TaskTime { get; set; }
public int Type_Id { get; set; }
public string VideoLink { get; set; }
[Required]
public int Language { get; set; }
public int? MinimumParticipants { get; set; }
public int? MaximumParticipants { get; set; }
public int? Rating { get; set; }
[Required]
public string CreatedBy { get; set; }
public virtual ICollection<Grade> Grades { get; set; }
public virtual ICollection<Category> Categories { get; set; }
public virtual ICollection<Subject> Subjects { get; set; }
public virtual ICollection<Room> Rooms { get; set; }
public virtual ICollection<Tool> Tools { get; set; }
}
DBContext class:
public ApplicationDbContext() : base("DefaultConnection", false)
{
}
public DbSet<Task> Tasks { get; set; }
public DbSet<TaskType> TaskTypes { get; set; }
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
You need to add the FK attribute on your navigation property. EF is creating Type_Id1 because Type_Id already exists (although it can't tell by convention it is the FK).
[ForeignKey("Type_Id")]
public virtual TaskType Type { get; set; }
https://msdn.microsoft.com/en-us/data/jj591583.aspx#Relationships

Sequence contains more than one matching element codefirst

I'm getting this error when trying to update relationship (one to one)
with fluent api this are my classes :
public class Organisation
{
[Key]
public int OrganisationId { get; set; }
public string organisationName { get; set; }
public string FirstName { get; internal set; }
public string LastName { get; internal set; }
public virtual ApplicationUser User { get; set; }
[Required]
public string ApplicationUserId { get; set; }
public int? OrganisationDetalisId { get; set; }
public virtual OrganisationDetalis OrDetalis { get; set; }
public virtual ICollection<Aeroa> aeroa { get; set; }
public virtual ICollection<Order> orders { get; set; }
}
public class OrganisationDetalis
{
[Key]
public int OrganisationDetalisId { get; set; }
//remove for clear code
public int OrganisationId { get; set; }
public virtual Organisation organisation { get; set; }
}
public DbSet<Organisation> organisation { get; set; }
public DbSet<OrganisationDetalis> OrDetalis { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<OrganisationDetalis>()
.HasKey(o => o.OrganisationId);
modelBuilder.Entity<Organisation>()
.HasOptional(ad => ad.OrDetalis).WithRequired(oo => oo.organisation);
}
but I keep getting that error when updating view nugget console
where is the problem?

Code first fluent api - table relationship

I have following tables and need to set relationship between them.
Model classes for the tables are as given
public class UserAction
{
public int ActionID { get; set; }
public string ActionName { get; set; }
public virtual ICollection<RoleScreenActionPermission> RoleScreenActionPermissions { get; set; }
}
public class Screen
{
public int ScreenID { get; set; }
public string ScreenName { get; set; }
public virtual ICollection<RoleScreenActionPermission> RoleScreenActionPermissions { get; set; }
}
public class ScreenAction
{
public int ScreenActionID { get; set; }
public int ScreenID { get; set; }
public int ActionID { get; set; }
public virtual Screen Screen { get; set; }
public virtual UserAction UserAction { get; set; }
}
public class RoleScreenActionPermission
{
public int RoleScreenActionPermissionID { get; set; }
public int ScreenActionID { get; set; }
public int RoleID { get; set; }
public virtual ScreenAction ScreenAction { get; set; }
public virtual Role Role { get; set; }
}
The talbe structure created is as:
Please help with setting the relationship correctly.
Try to remove all your own foreign keys from your classes. EF must make it.
upd:
public class Screen
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Action
{
public int Id { get; set; }
public string Name { get; set; }
}
public class ScreenAction
{
public int Id { get; set; }
public virtual Screen Screen { get; set; }
public virtual Action Action { get; set; }
}
public class RoleScreenActionPermission
{
public int Id { get; set; }
public virtual ScreenAction ScreenAction { get; set; }
public virtual Role Role { get; set; }
}

Eager Load Entity Framework Navigation Property error

I'm trying to eager load some child entities like so:
_context.Sites.Where(x => x.ID == siteID).Include(s => s.SiteLoggers).FirstOrDefault();
However, the error I am getting is:
A specified Include path is not valid. The EntityType 'MyProject.Dal.EF.Site' does not declare a navigation property with the name 'SiteLoggers'.
What is saying is correct, as MyProject.Dal.EF.Site does not exist, the object exists in MyProject.Domain.Entities.Site
What am I missing??? Thanks!
POCOs:
namespace MyProject.Domain.Entities
{
public class Site
{
public int ID { get; set; }
public int LocationID { get; set; }
public bool Active { get; set; }
public bool Deleted { get; set; }
public string Name { get; set; }
public virtual Location Location { get; set; }
public virtual IEnumerable<SiteLogger> SiteLoggers { get; set; }
}
}
namespace MyProject.Domain.Entities
{
public class SiteLogger
{
public int ID { get; set; }
public int UID { get; set; }
public int SiteID { get; set; }
public string Name { get; set; }
public int LocationID { get; set; }
public bool Active { get; set; }
public bool Deleted { get; set; }
public virtual Site Site { get; set; }
public virtual Location Location { get; set; }
}
}
You need to use ICollection instead of IEnumerable, because EF requires that your navigation properties are defined as ICollection<T>.
public virtual ICollection <SiteLogger> SiteLoggers { get; set; }