ASP.NET MVC EF Unable to determine the principal end of association - c#

I've encountered some problems with associations while using Entity Framework. Althought there are some other posts about that I couldn't make it working.
public class BaseJobOffer : IEntity
{
[Key, ForeignKey("File")]
public int Id { get; set; }
public string Name { get; set; }
public int FileId { get; set; }
public File File { get; set; }
}
public class File
{
public int Id { get; set; }
public string FileName { get; set; }
public string ContentType { get; set; }
public byte[] Content { get; set; }
public Enums.FileType FileType { get; set; }
public int JobOfferId { get; set; }
public virtual BaseJobOffer JobOffer { get; set; }
}
And the error says:
There was an error running selected code generator:
'Unable to retrieve metadata for Model.JobOffer'. Unable to determine
the principal end of association between the types
'Model.BaseJobOffer' and 'Model.File'. The principal end of this
association must be explicitly configured using either the
relationship fluent API or data annotations.'

See this article about ForeignKey attribute usage http://www.entityframeworktutorial.net/code-first/foreignkey-dataannotations-attribute-in-code-first.aspx
The ForeignKey attribute should be on either the ForeignKey property or the ForeignKeyID property
public class BaseJobOffer : IEntity
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
[ForeignKey("File")
public int FileId { get; set; }
//or
[ForeignKey("FileId")
public File File { get; set; }
}

Related

Code First Entity Framework - Column returns null becuase EF changed the name to include _ID

Entity framework changed the column name in the DB, and isn't giving me it's value.
Here are my classes:
public class Settings
{
[Key]
public int ID { get; set; }
public string Setting { get; set; }
public string MoreDetail { get; set; }
public SettingTypes Type { get; set; }
public SettingGroups SettingGroup { get; set; }
public int? MinMembership { get; set; }
public string DefaultValue { get; set; }
public int? ParentID { get; set; }
public int Order { get; set; }
}
public class SettingTypes
{
[Key]
public int ID { get; set; }
[MaxLength(35)]
public string TypeName { get; set; }
}
public class SettingGroups
{
[Key]
public int ID { get; set; }
[MaxLength(35)]
public string GroupName { get; set; }
}
In the DB you can see that it changed the name of the two columns:
When I try to loop through the results, type is null:
How do I retrieve this value? I've tried renaming the columns in the class and in the DB but that just breaks more things. What's the proper way to handle this?
Thanks!
Dangit, I figured it out. Spent way to much time doing so.
It was as simple as adding "virtual" to the properties:
public virtual SettingTypes Type { get; set; }
public virtual SettingGroups SettingGroup { get; set; }
Now I can address it like:
setting.Type.TypeName
Hope this saves someone else some time.

Cannot create controller with Entity Framework

Getting the following error when trying to create a controller.
There was an error running the selected code generator: "Unable to retrieve metadata for "ProjectName.Models.Tecnologia". One or more validation errors were detected during model generation:
ProjectName.DataContexts.Estadistica: EntityType "Estadistica" has no key defined. Define the key for this EntityType.
Estadisticas: EntityType: EntitySet: "Estadisticas" is based on type "Estadistica" that has no key defined.
Class Tecnologia:
public class Tecnologia
{
public int ID { get; set; }
public string Nombre { get; set; }
public List<Usuario> TutoresCorrectores { get; set; }
public List<FichaProyecto> FichasProyecto { get; set; }
}
Class Estadistica
public class Estadistica
{
public int Cantidad { get; set; }
public int Porcentaje { get; set; }
}
Class DataContexts.GestionProyectodbContext
public class GestionProyectodbContext : DbContext
{
public GestionProyectodbContext() : base("DefaultConnection")
{
}
public DbSet<Carrera> Carreras { get; set; }
public DbSet<Comentario> Comentarios { get; set; }
public DbSet<EstadoFicha> Estados { get; set; }
public DbSet<FichaProyecto> FichasProyectos { get; set; }
public DbSet<Grupo> Grupos { get; set; }
public DbSet<InformeAvance> InformesAvance { get; set; }
public DbSet<InstanciaAcademica> InstanciasAcademicas { get; set; }
public DbSet<InstanciaEvaluacion> InstanciasEvaluacion { get; set; }
public DbSet<PropuestaProyecto> PropuestasProyectos { get; set; }
public DbSet<Reunion> Reuniones { get; set; }
public DbSet<Rol> ListaRoles { get; set; }
public DbSet<Tecnologia> Tecnologias { get; set; }
public DbSet<TipoAplicacion> TiposAplicaciones { get; set; }
public DbSet<TipoCliente> TiposClientes { get; set; }
public DbSet<TipoProyecto> TiposProyectos { get; set; }
public DbSet<Usuario> Usuarios { get; set; }
public DbSet<InformeTarea> InformesTareas { get; set; }
public DbSet<Documento> Documentos { get; set; }
public DbSet<InformeCorreccion> InformesCorreccion { get; set; }
}
As seen, class "Estadistica" does not have an "ID" prop, but that's because I don't want to persist it in database. Id isn't even in the "GestionProyectodbContext" class, so it shouldn't be a problem. But when trying to create a controller por class "Tecnologia", an error saying that "Estadistica" has no key is popping. I don't know why this error is coming out, and I would some help from you if you somehow know why this happens.
PD: class "Tecnologia" is not even referring to class "Estadistica".
PD2: I know how to solve this error, but it's not the way I should be doing it, because I don't want to add an "ID" property into a class that I don't want to persist in the database.
You must have an mapped entity referencing Estadistica apply the NotMapped attribute to it.
you can also use the fluent api to ignore it:
protected override void OnModelCreating(DbModelBuilder modelBuilder) {
modelBuilder.Ignore<Estadistica>();
}
EF only works when it knows the primary key of the table, By default it recognizes the primary key with name Id, but if you don't have Id column name in your table then decorate its primary key with [Key] attribute.
public class Estadistica
{
[Key]
public int Cantidad { get; set; }
public int Porcentaje { get; set; }
}
hope it helps.

Entity Framework foreign key not found during migration

I'm experiencing an unexpected error when setting up a migration after adding keys and foreign keys to my data model. I'm using VS2013 Express, with .NET framework 4.5.
When creating a data model for Entity Framework, because the relationship keys between classes aren't what is expected by convention, I'm using data annotations as outlined in the MS Data Developer Center. Here's the class code:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace BacklogTracker.Models
{
public class WorkOrder
{
[Key]
public string woNum { get; set; }
public string woClosingStatus { get; set; }
[ForeignKey("ID")]
public virtual ICollection<Note> woNotes { get; set; }
[ForeignKey("machSN")]
public virtual Machine woMachine { get; set; }
[ForeignKey("ID")]
public virtual ICollection<Segment> woSegments { get; set; }
}
public class Machine
{
[Key]
public string machSN { get; set; }
public string machLocation { get; set; }
public string machModel { get; set; }
}
public class Segment
{
[Key]
public int ID { get; set; }
public uint segNum { get; set; }
public string segRepair { get; set; }
[ForeignKey("ID")]
public virtual ICollection<Note> segNotes { get; set; }
}
public class Note
{
[Key]
public int ID { get; set; }
public DateTime notetimestamp { get; set; }
public string notestring { get; set; }
}
}
However, when I try to perform a migration after updating the model by performing enable-migrations in the package manager console, I get the following error:
The ForeignKeyAttribute on property 'woMachine' on type
'BacklogTracker.Models.WorkOrder' is not valid. The foreign key name
'machSN' was not found on the dependent type
'BacklogTracker.Models.WorkOrder'. The Name value should be a comma
separated list of foreign key property names.
Why is my foreign key name 'machSN' not being found?
I think you have some errors in your model. Default Code First convention for ForeignKey relationship expected to have declared a foreign key property in the dependend end (WorkOrder) that match with primary key property of the principal end (Machine). It is not necessary that they have the same name, check this link. So, declare a property named machSN in your WorkOrder class:
public class WorkOrder
{
[Key]
public string woNum { get; set; }
public string woClosingStatus { get; set; }
public virtual ICollection<Note> woNotes { get; set; }
public string machSN { get; set; }
[ForeignKey("machSN")]
public virtual Machine woMachine { get; set; }
public virtual ICollection<Segment> woSegments { get; set; }
}
You can find other errors in the woNotes and woSegments navigation properties. In this side of a one-to-many relationship you don't declare a FK, is in the other side, in Note and Segment classes, for example:
public class Note
{
[Key]
public int ID { get; set; }
public DateTime notetimestamp { get; set; }
public string notestring { get; set; }
[ForeignKey("Order)]
public string woNum { get; set; }
public virtual WorkOrder Order{get;set;}
}
Delete also in the Segment class the ForeignKey attribute over segNotes navigation property for the same reasons explained before.
public class Segment
{
[Key]
public int ID { get; set; }
public uint segNum { get; set; }
public string segRepair { get; set; }
public virtual ICollection<Note> segNotes { get; set; }
}

Entity Framework 6 - foreign key issue

I have the following model using EF6, where I'm trying to link a 'ContentArticleHOAsubdivision' entity to a 'SubdivisionHOA':
public partial class ContentArticleHOAsubdivision
{
public int Id { get; set; }
[ForeignKey("ContentArticleHOA")]
public long ContentArticleId { get; set; }
[ForeignKey("SubdivisionsHOA")]
public short SubdivisionId { get; set; }
public virtual ContentArticleHOA ContentArticleHOA { get; set; }
public virtual ICollection<SubdivisionHOA> SubdivisionsHOA { get; set; }
}
public partial class SubdivisionHOA
{
public short Id { get; set; }
public string Name { get; set; }
[ForeignKey("TopTierDivisionHOA")]
public byte TopTierDivisionId { get; set; }
public virtual TopTierDivisionHOA TopTierDivisionHOA { get; set; }
}
I get the error:
The foreign key component 'SubdivisionId' is not a declared property on type 'SubdivisionHOA'. Verify that it has not been explicitly excluded from the model and that it is a valid primitive property.
The 'Id' property in SubdivisionHOA I'm trying to link on needs to be named 'Id' as that's the name of the actual column in the database, so I'm not sure what I need to do?
I've tried adding [InverseProperty("Id")] before the [ForeignKey] attributes but get the same error.
Basicly the foreign key usage in EntityFramework seems like this:
public partial class ContentArticleHOAsubdivision
{
public int Id { get; set; }
...
public virtual ICollection<SubdivisionHOA> SubdivisionsHOAs { get; set; }
}
public partial class SubdivisionHOA
{
public short Id { get; set; }
...
public int ContentArticleHOAsubdivisionId { get; set; }
[ForeignKey("ContentArticleHOAsubdivisionId")]
public virtual ContentArticleHOAsubdivision ContentArticleHOAsubdivision { get; set; }
}
Just based on your code, and I have discard some unknown stuffs.

Relationships in Entity Framework Code First

yesterday I created database in Management Studio and now I want to create it in program using EF Code First.
Here is link to my database: http://s11.postimg.org/6sv6cucgj/1462037_646961388683482_1557326399_n.jpg
And what I did:
public class GameModel
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public DateTime CreationTime { get; set; }
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
public string TotalTime { get; set; }
public DateTime RouteStartTime { get; set; }
public DateTime RouteEndTime { get; set; }
public int MaxPlayersPerTeam { get; set; }
public int CityId { get; set; }
public int CreatorId { get; set; }
[InverseProperty("Id")]
[ForeignKey("CreatorId")]
//public int TeamId { get; set; }
//[ForeignKey("TeamId")]
public virtual UserModel Creator { get; set; }
public virtual CityModel City { get; set; }
//public virtual TeamModel WinnerTeam { get; set; }
}
public class RegionModel
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<CityModel> Cities { get; set; }
}
public class CityModel
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public int RegionId { get; set; }
public virtual RegionModel Region { get; set; }
public virtual ICollection<UserModel> Users { get; set; }
public virtual ICollection<GameModel> Games { get; set; }
}
public class UserModel
{
[Key]
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Login { get; set; }
public string Password { get; set; }
public string Email { get; set; }
public DateTime RegistrationDate { get; set; }
public string FacebookId { get; set; }
public int CityId { get; set; }
public virtual CityModel City { get; set; }
public virtual IEnumerable<GameModel> Games { get; set; }
}
For now I wanted to create 4 tables but I have some problems... I want to make CreatorId in GameModel, but it doesn't work... When i wrote UserId instead of CreatorId it was working ( without [InverseProperty("Id")] and [ForeignKey("CreatorId")]).
This is what i get:
The view 'The property 'Id' cannot be configured as a navigation property. The property must be a valid entity type and the property should have a non-abstract getter and setter. For collection properties the type must implement ICollection where T is a valid entity type.' or its master was not found or no view engine supports the searched locations.
edit:
I changed it like this:
public int CityId { get; set; }
public int CreatorId { get; set; }
[ForeignKey("CityId")]
public virtual CityModel City { get; set; }
[ForeignKey("CreatorId")]
public virtual UserModel Creator { get; set; }
And there is another problem.
The view 'Introducing FOREIGN KEY constraint 'FK_dbo.UserModels_dbo.CityModels_CityId' on table 'UserModels' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
Could not create constraint. See previous errors.' or its master was not found or no view engine supports the searched locations.
And I have no idea how to solve it.
The InversePropertyAttribute specifies, which navigation property should be used for that relation.
A navigation property must be of an entity type (the types declared in your model, GameModel for example) or some type implementing ICollection<T>, where T has to be an entity type. UserModel.Id is an int, which clearly doesn't satisfy that condition.
So, the inverse property of GameModel.Creator could be UserModel.Games if you changed the type to ICollection<GameModel>, or had to be left unspecified. If you don't specify an inverse property, EF will try to work everything out on its own (in this case it would properly recognize GameModel.Creator as a navigation property, but UserModel.Games would most likely throw an exception, as it is neither an entity type, nor does it implement ICollection<T> with T being an entity type, nor is it a primitive type from a database point of view). However, EF's work-everything-out-by-itself-magic doesn't cope too well with multiple relations between the same entity types, which is when the InversePropertyAttribute is needed.
A quick example that demonstrates the problem:
class SomePrettyImportantStuff {
[Key]
public int ID { get; set; }
public int OtherId1 { get; set; }
public int OtherId2 { get; set; }
[ForeignKey("OtherId1")]
public virtual OtherImportantStuff Nav1 { get; set; }
[ForeignKey("OtherId2")]
public virtual OtherImportantStuff Nav2 { get; set; }
}
class OtherImportantStuff {
[Key]
public int ID { get; set; }
public virtual ICollection<SomePrettyImportantStuff> SoldStuff { get; set; }
public virtual ICollection<SomePrettyImportantStuff> BoughtStuff { get; set; }
}
Here, EF knows that it has to generate 2 FKs from SomePrettyImportantStuff to OtherImportantStuff with the names Id1 and Id2, but it has no way to tell which of the IDs refers to the entity where it was sold from and which is the one it was bought from.
Edit: How to fix the cyclic reference problem
To fix that problem, your context class should override OnModelCreating and configure the foreign keys which shouldn't cascade on delete accordingly, like this:
protected override void OnModelCreating(DbModelBuilder builder)
{
builder.Entity<CityModel>().HasMany(c => c.Users).WithRequired(u => u.City)
.HasForeignKey(u => u.CityId).WillCascadeOnDelete(value: false);
// Add other non-cascading FK declarations here
base.OnModelCreating(builder);
}

Categories

Resources