Code First nullable Foreign Key not recognized - c#

I made a .Net MVC project. First I have created a ClassLibrary with all models and Db Contexts and i used this library in working with database. Now i want to use this class library in another project from another solution. I made a reference to class library but this new project does not recognize nullable Foreign keys (such as "strings" or nullable "Int"). Error ocuurs on runtime.
Class example
[Table("PORT_CALLS")]
public class PORT_CALLS
{
[Key]
public Int64 SID { get; set; }
[ForeignKey("SHIP_CALLS")]
public Int64 SHIP_CALL_SID { get; set; }
public virtual SHIP_CALLS SHIP_CALLS{ get; set; }
[ForeignKey("MNG_OPERATORS")]
public Int64 ? OPERATOR_SID { get; set; }
[JsonIgnore]
public virtual MNG_OPERATORS MNG_OPERATORS { get; set; }
public Decimal ? FORE_DRAUGHT { get; set; }
public Decimal ? MID_SHIP_DRAUGHT { get; set; }
public Decimal ? AFT_DRAUGHT { get; set; }
public Decimal ? AIR_DRAUGHT { get; set; }
public Int16 ? IS_TANKER { get; set; }
}
Error: Entity Type has no key defined Define the key for this EntityType (this error occurs for all nullable foreign keys)

You should apply the [ForeignKey] attribute to the SHIP_CALLS property with the name of the property that offers the foreign key:
[ForeignKey("SHIP_CALL_SID")]
public virtual SHIP_CALLS SHIP_CALLS{ get; set; }

Related

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.

Using nullable for Foreign Key in Entity Framawork

I use EF Code First approach in an ASP.NET MVC project and I have PK-FK relations on several entities as shown below:
public class Staff
{
public int Id { get; set; }
//Foreign key for Project
public int ProjectId { get; set; }
public virtual Project Project { get; set; }
}
public class Project
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Staff> Staffs { get; set; }
}
On the other hand, sometimes there is a need to use nullable FK values and in that case I create dummy record as N/A as FK is required property that seems to em ugly :( I know I can easily use nullable value for the related FK property, but I am not sure if it is a good approach or not. And what is the pros and cons using this approach (I know a pros of required FK : Data integrity :)
Secondly, should I use 0 or null value for the nullable FK? Why?
Adding a dummy record is not right, the correct approach here is to use an int? for the foreign key relation, see here:
If the data type of GradeId is nullable integer, then it will create a
null foreign key.
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public int? GradeId { get; set; }
public Grade Grade { get; set; }
}
The above code snippet will create a nullable GradeId column in the
database because we have used Nullable<int> type (? is a shortcut for
Nullable<int>)
An alternative approach would be removing ProjectId from the staff (Convention 3 in the above document):
public class Staff
{
public int Id { get; set; }
public virtual Project Project { get; set; }
}
public class Project
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Staff> Staffs { get; set; }
}

Different behavior across domain objects for same properties in Entity Framework Core 2

I am new to .NET Core and using EF Core 2
My domain objects are all derived from a base class with some audit fields on it that get set on SaveChanges as needed:
(Simplified below)
public abstract class AuditableEntity
{
public DateTime CreatedOn { get; set; }
[ForeignKey("CreatedBy")]
public Guid? CreatedByWebUserId { get; set; }
public WebUser CreatedBy { get; set; }
public DateTime? UpdatedOn { get; set; }
[ForeignKey("UpdatedBy")]
public Guid? UpdatedByWebUserId { get; set; }
public WebUser UpdatedBy { get; set; }
public DateTime? DeletedOn { get; set; }
[ForeignKey("DeletedBy")]
public Guid? DeletedByWebUserId { get; set; }
public WebUser DeletedBy { get; set; }
}
On add-migration, I get the error:
Unable to determine the relationship represented by navigation property
'Address.CreatedBy' of type 'WebUser'. Either manually configure the
relationship, or ignore this property using the '[NotMapped]' attribute or by
using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.
Address is one of the classes derived from AuditableEntity:
(Simplified below)
public class Address : AuditableEntity
{
public Guid Id { get; set; }
public string Nickname { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string Address3 { get; set; }
public string City { get; set; }
public string StateProvince { get; set; }
public string PostalCode { get; set; }
public string CountryCode { get; set; }
public decimal Latitude { get; set; }
public decimal Longitude { get; set; }
}
However, I have several objects that use the same "agent and timestamp" pair pattern similar to the above that work just fine such as:
public DateTime? VerifiedOn { get; set; }
[ForeignKey("VerifiedBy")]
public Guid? VerifiedByWebUserId { get; set; }
public WebUser VerifiedBy { get; set; }
The error always comes from Address, and if I remove the base class from Address everything works fine (meaning, these fields get successfully applied to my 15+ other domain objects).
The issue seemingly stems from WebUser having a reference to Address:
(Simplified below)
public class WebUser : AuditableEntity
{
public Guid Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string EmailAddress { get; set; }
public string Phone1 { get; set; }
public string Phone1Type { get; set; }
public string Phone2 { get; set; }
public string Phone2Type { get; set; }
[ForeignKey("AddressId")]
public Address Address { get; set; }
public Guid? AddressId { get; set; }
}
What is the correct way of creating these references prioritizing keeping the FK constraints (over keeping the ability to navigate)?
The problem is unrelated to the usage of a base class (the same will happen if you remove the base class, but copy its properties to Address class), but the multiple cross references between the two classes.
By convention EF Core tries to automatically "pair" navigation properties of the two entities in order to form a single relationship, which succeeds in most of the cases. However in this case the WebUser has Address type navigation property and Address class has WebUser type navigation property (actually 3).
Since all they have associated FK property via ForeignKey data annotation, EF Core should be able to correctly identify them as different one-to-many relationships, but it doesn't. Not only it fails with the exception in question, but also doesn't create FK relationships for the WebUser.
Everything works correctly if the base class contains only 1 WebUser type of navigation property, so I'm assuming thet unfortunately you are hitting some current EF Core bug.
As a workaround until they fixed it, I would suggest explicitly configuring the problematic relationships using fluent API, by overriding the OnModelCreating and adding the following code:
var auditableEntityTypes = modelBuilder.Model.GetEntityTypes().Where(t => t.ClrType.IsSubclassOf(typeof(AuditableEntity)));
var webUserNavigations = new[] { nameof(AuditableEntity.CreatedBy), nameof(AuditableEntity.DeletedBy), nameof(AuditableEntity.UpdatedBy) };
foreach (var entityType in auditableEntityTypes)
{
modelBuilder.Entity(entityType.ClrType, builder =>
{
foreach (var webUserNavigation in webUserNavigations)
builder.HasOne(typeof(WebUser), webUserNavigation).WithMany();
});
}
i.e. for each entity class that derives from AuditableEntity we explicitly configure the 3 WebUser reference navigation properties to be mapped to 3 separate one-to-many relationships with no inverse collection navigation properties. Once we do that, EF Core has no problem to correctly map the WebUser.Address FK association.

Entity Framework --Unable to determine the principal end of an association between the types?

I am creating entities using code first schema but when run the application its generating exception
Unable to determine the principal end of an association between the types 'WebApplication1.Models.DateOfProject' and 'WebApplication1.Models.Projects'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.
My scenario is to implement 1.1 relation between Projects and DateOfProjects such that 1 project has 1 dateOfProject.
My code is
public class Projects
{
[Key()]
[DatabaseGenerated(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity)]
public int ProjectId { get; set; }
public string ProjectTitle { get; set; }
public string ProjectDescriptions { get; set; }
public DateOfProject DateOfProject { get; set; }
public virtual ICollection<ApplicationUser> ApplicationUser { get; set; }
public virtual ICollection<TaskSheetManagement> TaskSheetManagement { get; set; }
}
public class DateOfProject
{
public int DateOfProjectId { get; set; }
[ForeignKey("ProjectId")]
public Projects Projects { get; set; }
public DateTime DateOfProjectCreation { get; set; }
public Nullable<DateTime> ExpectedCompletionDate { get; set; }
public Nullable<DateTime> ProjectCompletionDate { get; set; }
}
and inside DbContextClass inOnModelCreating function
modelBuilder.Entity<Projects>().HasKey(pk => pk.ProjectId).ToTable("Projects");
modelBuilder.Entity<DateOfProject>().HasKey(pk => pk.DateOfProjectId).ToTable("DateOfProject");
modelBuilder.Entity<Projects>().HasRequired(p => p.DateOfProject).WithRequiredPrincipal(c => c.Projects);
I could not just resolve that problem.
If you want a 1 : 1 relationship you have to remove the [ForeignKey("ProjectId")] Attribute. For 1: 1 relationships the Primary Key is used. If you want a separate foreign Key column it is a 1 : * relationship.

Entity Framework Code First - Reference same table

I am still starting with Entity Framework Code First. I want to be able to select a Resource from list when creating a new resource. How do I reference a Resource with a Resource model.
public class Resource
{
public int ResourceId { get; set; }
[Required]
[DataType(DataType.EmailAddress)]
[EmailAddress]
public string EmailAddress { get; set; }
[Required]
public string Password { get; set; }
public string FullName { get; set; }
public int TimeManagerId { get; set; }
public int TravelManagerId { get; set; }
public int OvertimeManagerId { get; set; }
public int AbsenceManagerId { get; set; }
public virtual Resource TimeManager { get; set; }
public virtual Resource TravelManager { get; set; }
public virtual Resource OvertimeManager { get; set; }
public virtual Resource AbsenceManager { get; set; }
}
I think you're pretty close! If you want to do this by convention, you can change the foreign keys in your model to the form of [navigation property name][principal primary key property name]. Specifically, change Id to ResourceId so it matches the primary of the table you're referencing (which happens to be itself)...
public int TimeManagerResourceId { get; set; }
public int TravelManagerResourceId { get; set; }
public int OvertimeManagerResourceId { get; set; }
public int AbsenceManagerResourceId { get; set; }
Since you're just starting with EF code first, I'd recommend you install the Entity Framework Power Tools. You'll be able to right-click on the .cs file containing your DbContext, and it'll generate a read-only diagram of the mappings.
Try it out with your current model... right-click on entity in the diagram and view Table Mappings. You'll see EF wasn't able to figure out your foreign keys and created 4 more for you. Once you make the changes above, generate the diagram again and see the difference.
Edit: Docs on code first conventions... http://msdn.microsoft.com/en-us/data/jj679962.aspx

Categories