Data annotations not create one-to-many object references - c#

I'm missing something when using the data annotations.
This is my first class
[Table("PriceFeed")]
public class PriceFeed : History
{
public PriceFeed()
{
this.Votes = new List<PriceVote>();
this.History = new List<PriceFeed__History>();
}
[Key]
public long Id { get; set; }
[ForeignKey("Store")]
public long Store_Id { get; set; }
[ForeignKey("Item")]
public long Item_Id { get; set; }
[Required]
public decimal Price { get; set; }
public Store Store { get; set; }
public Item Item { get; set; }
public virtual ICollection<PriceFeed__History> History { get; set; }
}
And this is my second class
[Table("PriceFeed__History")]
public class PriceFeed__History : History
{
[Key]
public long Id { get; set; }
[ForeignKey("PriceFeed")]
public long PriceFeed_Id { get; set; }
[Required]
public decimal Price { get; set; }
public virtual PriceFeed PriceFeed { get; set; }
}
When I run the add-migration, it creates the database correctly but when I try to access PriceFeed.History it gives me an error
{"Message":"An error has occurred.","ExceptionMessage":"A specified Include path is not valid. The EntityType 'Verdinhas.Web.Contexts.PriceFeed' does not declare a navigation property with the name 'PriceFeed__History'."
I always worked with API Fluent and typed by myself the code like
.Entity<Student>()
.HasRequired<Standard>(s => s.Standard)
.WithMany(s => s.Students)
.HasForeignKey(s => s.StdId);
But now I'm using the data annotations and when I generate the migration, it does not create the "withmany" like the above.
What am I doing wrong?

The issue has nothing to do with Data Annotations which seems to be correct in your model.
As mentioned in the comments, the exception is caused by a code that tries to use Include method with string "'PriceFeed__History" - you seem to think that you should specify the related entity types, but in fact you need to specify the navigation property names, which in your case is "History".

Related

eventlog shows invalid column name although I don't have that in my model

I have the following database model class called positions:
public class Positions
{
public string? Id { get; set; }
public string? ArticlePLU { get; set; }
public string? ArticleName { get; set; }
public string? ArticleGroupPlu { get; set; }
public string? ArticleGroupName { get; set; }
public string? MenuId { get; set; }
public string? MenuName { get; set; }
public string? MenuLineId { get; set; }
public string? MenuLineName { get; set; }
public decimal Quantity { get; set; }
public decimal Price { get; set; }
public List<Vat>? Vat { get; set; }
public List<AdditionalCost>? AdditionalCost { get; set; }
public List<Components>? Components { get; set; }
public Comment Comment { get; set; }
[ForeignKey("Orders")]
public string? OrdersId { get; set; }
}
I also have the following class called Comment:
public class Comment
{
public string? Id { get; set;}
public string? Type { get; set;}
public string? Value { get; set;}
[ForeignKey("Components")]
public string? ComponentsId;
[ForeignKey("Positions")]
public string? PositionsId;
}
The class comment is a child of positions but it can also be a child of components, which itself is a child of positions, but I don't think thats relevant to the problem right now.
The eventlog of IIS shows that whenever I try to send data with Postman it cannot recognize a column called "CommentId" which does not exist in any classes and isnt referenced anywhere. My guess is that EntityFramework, which im using, is doing something in the background because I have not configured everything correctly. The 'Comment' data is supposed to be in another table. When the data is received, the Comment should get an own unique Id through my controller class and EF handles the foreign key.
Since the Comment is the non nullable Child of the Position, Entity Framework automatically add Foreign KeyCommentId
column to the table Positions. In order to solve this, you can make the Comment to be Nullable by adding ? in the Comment Property in Position model
public Comment? Comment { get; set; }
This will remove EF Core from automatically add new column CommandId to table Positions
Edit :
Configure using Fluent Api the relationship between Comment and Position..
modelBuilder.Entity<Position>()
.HasOne(p => p.Comment)
.WithOne()
.HasForeignKey<Comment>(p => p.PositionsId);
Just put this inside your DbContext class. Learn more here : https://learn.microsoft.com/en-us/ef/core/modeling/relationships?tabs=fluent-api%2Cfluent-api-simple-key%2Csimple-key

'Invalid Column Name' Error After Upgrading from Asp.net core 2.0 to 2.1

I've revisited my web site recently and had to upgrade from ASP.net MVC (DBF) core 2.0 to 2.1.
Since doing so I'm getting the following error...
SqlException: Invalid column name 'MovieTitleId'. Invalid column name 'MovieTitleId'.
Yet there is no such field 'MovieTitleId' in any part of my code or db.
The error occurs only when the site is accessing the 'many table' Scenes
(there is a one-to-many relationship set up in the db with FKs.. Movie > Scenes)
This is the Scene class..
public partial class Scene
{
[Key]
public int SceneId { get; set; }
[ForeignKey("TitleId")]
public int? TitleId { get; set; } // foreign key from Movie
[ForeignKey("LocationSiteId")]
public int? LocationSiteId { get; set; }
[ForeignKey("LocationAliasId")]
public int? LocationAliasId { get; set; }
public string Notes { get; set; }
public int? SceneOrder { get; set; }
public string TitleList { get; set; }
public LocationAlias LocationAlias { get; set; }
public LocationSite LocationSite { get; set; }
public Movie Movie { get; set; }
}
And this is the Movie class which on the 'one side' and call Scenes on a typical 'Master/Detail' type web page...
public partial class Movie
{
public Movie()
{
Scenes = new HashSet<Scene>();
}
[Key]
public int TitleId { get; set; }
[Required]
public string Title { get; set; }
[DisplayName("Title")]
public string ParsedTitle { get; set; }
[DisplayName("Year")]
public int? TitleYear { get; set; }
public string ImdbUrl { get; set; }
public string Summary { get; set; }
public bool? ExcludeTitle { get; set; }
public bool? Widescreen { get; set; }
[DisplayName("Title")]
public override string ToString()
{
return Title + " (" + TitleYear + ")";
}
public ICollection<Scene> Scenes { get; set; }
}
The error occurs in the MoviesController.cs...
Movie movie = _context.Movies.Find(id);
ViewBag.Scenes = _context.Scenes
.Where(s => s.TitleId == id)
.Include(s => s.LocationSite)
.Include(s => s.LocationSite.LocationPlace)
.OrderBy(s => s.SceneOrder).ToList();
Everything used to work fine until i upgraded to core 2.1.
I can't even recall there ever being a field called 'MovietitleId' which is actually 'TitleId'.
Is the error msg concatenating the model 'Movie' and column 'TitleId' somehow?
Try adding virtual keyword for your foreign key. Also the ForeignKey Data Annotation should be on that property where you have declared your virtual property just like below. So it should be something like this:
Scene.cs
public int TitleId { get; set; }
[ForeignKey("TitleId")
public virtual Movie Movie { get; set; }
Why virtual?
If you declare your property virtual your virtual property (by default) won't be loaded right away when querying the main object. It will be retrieved from the database ONLY if you try to access it. This is called lazy loading.
If you want to know why to use virtual in detail, you may visit this link: Why are foreign keys in EF Code First marked as virtual?
Hope this helps.

EF Core 2.2.6: Unable to map 2 foreign keys to the same table

I am having issues trying to map two fields that are foreign keys into the same table. The use case is for a modifier and creator. My class already has the Ids, and then I wanted to add the full User object as virtual.
I am using a base class so that each of my tables have the same audit fields:
public class Entity
{
public long? ModifiedById { get; set; }
public long CreatedById { get; set; } = 1;
[ForeignKey("CreatedById")]
public virtual User CreatedByUser { get; set; }
[ForeignKey("ModifiedById")]
public virtual User ModifiedByUser { get; set; }
}
The child class is very simple:
public class CircleUserSubscription : Entity
{
[Required]
public long Id { get; set; }
public long SponsorUserId { get; set; }
[ForeignKey("SponsorUserId")]
public virtual User User { get; set; }
public long TestId { get; set; }
[ForeignKey("TestId")]
public virtual User Test { get; set; }
}
This is a standard junction table.
When I try to generate the migration, I am getting errors that I don't understand fully.
Unable to determine the relationship represented by navigation property 'CircleUserSubscription.User' of type 'User'. Either manually configure the relationship, or ignore this property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.
I tried what this answer had, but the code is basically the same: https://entityframeworkcore.com/knowledge-base/54418186/ef-core-2-2---two-foreign-keys-to-same-table
An inverse property doesn't make sense since every table will have a reference to the user table.
For reference, here is the User entity:
public class User : Entity
{
public long Id { get; set; }
public string Username { get; set; }
public string Email { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
I am hoping you all can help me out, TIA :)
EDIT: One thing to note, all of this worked fine when the entity class was as follows:
public class Entity
{
public long? ModifiedById { get; set; }
public long CreatedById { get; set; } = 1;
}
It was only after I added the entity that things went awry.

Entity Framework .Include throwing NullReferenceException

I have a very basic EF setup that is throwing an odd error when trying to populate a navigation property by using .Include. Here are the entity Models:
public class LineGroup
{
public int ID { get; set; }
public string Name { get; set; }
public bool IsActive { get; set; }
public ICollection<LineGroupMember> LineGroupMembers { get; set; }
}
public class LineGroupMember
{
public int ID { get; set; }
public int Extension { get; set; }
public string Name { get; set; }
public int Permissions { get; set; }
public bool IsLoggedIn { get; set; }
public int LineGroupID { get; set; }
internal LineGroup LineGroup { get; set; }
}
I am using these through an injected DB context, and can query each just fine without using navigation properties. I can also query the LineGroups and include the LineGroupMembers property just fine, like so:
var LineGroups = _context.LineGroups.Include(l => l.LineGroupMembers).ToList();
This load all of the line groups into a list that has a correctly working "LineGroupMembers" collection for each Line Group. However, if I try
var lineGroupMembers = _context.LineGroupMembers.Include(m => m.LineGroup).ToList();
I get "NullReferenceException" with no helpful details. Any ideas why the navigation property will work one way and not the other? There are no null values in either database table...
Make your navigation property public
public LineGroup LineGroup { get; set; }
If it is internal it won't be picked up by default by EF. You could also add explicit fluent mapping to force EF to recognize it as well.

Entity Framework - Invalid column name 'CourseLesson_Id'

After trying to execute the following query:
List<CourseLesson> courseLessons = (from cl in context.CourseLessons
.Include(x => x.CourseLessonTestQuestions)
select cl).ToList();
I get the the error Invalid column name 'CourseLesson_Id'.
My models and DataContext looks like this(this is from a test project I've created to repreduce the problem)
public class CourseLesson
{
public int Id { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public ICollection<CourseLessonTestQuestion> CourseLessonTestQuestions { get; set; }
}
public class CourseLessonTestQuestion
{
public int Id { get; set; }
public int CourseLessonId { get; set; }
[ForeignKey(nameof(CourseLessonId))]
public CourseLesson CourseLesson { get; set; }
public int? ReturnCourseLessonId { get; set; }
[ForeignKey(nameof(ReturnCourseLessonId))]
public CourseLesson ReturnCourseLesson { get; set; }
}
I have 2 foreign keys that point to the same table and I'm assuming EF is trying to create or map something that doesn't really exist.
After reading for a while I've found a way to fix my problem in (this answer) with the following code:
modelBuilder.Entity<CourseLessonTestQuestion>()
.HasOptional(cltq => cltq.ReturnCourseLesson)
.WithMany(x => x.CourseLessonTestQuestions);
What really bugs me about this situation is why everything works when I use the Fluent API, but it doesn't work with the ForeignKey attribute? This looks like something that could lead to future problems and I want to know what is really happening.
And the real question is there a solution for fixing this problem without the Fluent API? Like using attributes or some other convention?
I'm using Entity Framework 6.1.3
Solution without Fluent API, but with the help of InversePropertyAttribute, whose constructor's argument is the name of corresponding CourseLessonTestQuestion's property:
public class CourseLesson
{
public int Id { get; set; }
public string Title { get; set; }
public string Content { get; set; }
[InverseProperty("CourseLesson")]
public ICollection<CourseLessonTestQuestion> CourseLessonTestQuestions { get; set; }
[InverseProperty("ReturnCourseLesson")]
public ICollection<CourseLessonTestQuestion> ReturnCourseLessons { get; set; }
}

Categories