Is it possible to create a Domain Class which has Multiple FK Columns to same PK? - sql

I'm a newbie to designing database.
I have problem how to define a domain class which has multiple foreign keys linked with a same primary key.
Here is my model:
namespace OceanFmsSystem.Domain
{
public class ExportTemplate
{
public int Id { get; set; }
public List<ExportBooking> ExportBookings { get; set; }
public string TemplateName { get; set; }
public int CustomerId { get; set; }
public string Incoterms { get; set; }
public string IncotermsDetail { get; set; }
public string PaymentTerm{ get; set; }
public int CountryOriginId { get; set; }
public int CountryDestinationId { get; set; }
}
}
What I want to do is that CountryOriginId & CountryDestinationId should refer to the below class as foreign keys:
namespace OceanFmsSystem.Domain
{
public class Country
{
public int Id { get; set; }
public string CountryCode { get; set; }
public string CountryName { get; set; }
}
}
As far as I know, in EF Core there is an convention which I should name a foreign key as below for migration from code to database.
public type ClassNameOfPrimaryKeyId { get; set;}
Is there any possible way to make this happens?

Yes, possible. Your class should look like this:
public class ExportTemplate
{
//...
public int CountryOriginId { get; set; }
public Country CountryOrigin { get; set; }
public int CountryDestinationId { get; set; }
public Country CountryDestination { get; set; }
}
EF is smart enough to figure the Ids by convention. If you do not wish to follow the convention you can use [ForeignKey] attribute on the properties to configure the FK:
[ForeignKey("Origin")]
public int MyOriginId { get; set; }
public Country Origin { get; set; }

Related

How to establish one-to-many relationship for a code-first approach?

I'm trying to build a recipe app for my spouse. I'm trying to set it up so she can add new recipes to the database as the app grows.
When adding new recipe, she will have three drop-down to pick from to construct her new recipe ingredients. First one will contain a list of ingredients that she can choose from, the second one a list of measuring units and the third one a list of quantities.
Here is what I got so far. Am I heading in the right direction or am I off? I'm using Entity Framework with a code-first approach:
public class Recipes
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Image { get; set; }
}
public class Units model
{
[Key]
public int Id { get; set; }
public string UnitName { get; set; }
}
public class UnitQty
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
}
public class IngredientsModel
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
}
public class RecipeIngredients
{
public int Id { get; set; }
public int RecipesId { get; set; }
[ForeignKey("RecipesId")]
public Recipes Recipes { get; set; }
public int IngredientsModelId { get; set; }
[ForeignKey("IngredientsModelId")]
public IngredientsModel IngredientsModel { get; set; }
public int UnitQtyId { get; set; }
[ForeignKey("UnitQtyId")]
public UnitQty UnitQty { get; set; }
public int UnitsModelId { get; set; }
[ForeignKey("UnitsModelId")]
public UnitsModel UnitsModel { get; set; }
}
After creating the table, controller and the views, this is what I get in the recipe ingredients index view.
Any suggestion will be more than welcome please and thank you
RecipeIngredient class's view
First of all. You are over engineering your domain model. On relational databases Join is bottleneck you should prevent from joins if it doesn't helps you.
public class Recipt
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Image { get; set; }
public ICollection<RecipeIngredient> Ingredients { get; set; }
}
public class IngredientModel
{
public int Id { get; set; }
public string Name { get; set; }
public IngredientUnit UnitType { get; set; } // Unit model is best to be added here. if it doesn't change in a single IngredientModel.
}
public class RecipeIngredient
{
public int Id { get; set; }
public int UnitQuantiy { get; set; } // No need to more classes.
public IngredientModel Model { get; set; }
public Recipt Recipt { get; set; }
}
public Enum IngredientUnitType // Same Unit Model but less database relation as its small finite collection.
{
Killogram,
Count,
....
}
and according to the Microsoft documents its best to use fluentApi configuration for the relations.
Override this method in your Context:
protected override void OnModelCreating(ModelBuilder builder)
{
builder.Entity<Recipt>.HasMany(P => P.Ingredients).WithOne(P => P.Recipt);
builder.Entity<RecipeIngredient>.HasOne(P => P.Model);
// There is no need to explicit foreign key definition. but you can explicitly define your foreign keys.
}
And for the last part. in Views you can use extra models called ViewModels.
As above domain turned to a minimal domain you just need to pass a list of IngredientModels to your view to complete your View.

Object reference not set to an instance of an object in .net core

I have two model class as;
public class MessageDetailModel
{
[Key]
public int messageDetailsId { get; set; }
public MessageModel messageModel { get; set; }
public string detail { get; set; }
public int senderId { get; set; }
public int customerId { get; set; }
public string phone { get; set; }
public DateTime date { get; set; }
}
and
public class MessageModel
{
[Key]
public int messageId { get; set; }
public int senderId { get; set; }
public int customId { get; set; }
public bool ReadInfo { get; set; }
public virtual List<MessageDetailModel> MessageDetails { get; set; }
}
and it is my context class ;
public virtual DbSet<MessageDetailModel> messageDetails { get; set; }
public virtual DbSet<MessageModel> messages { get; set; }
public virtual DbSet<PersonModel> persons { get; set; }
public virtual DbSet<DirectoryModel> directory { get; set; }
I am trying to get messageId over MessageDetailModel but messageId returns as 0 and I have that error "Object reference not set to an instance of an object"
Console.WriteLine(k.messageModel.messageId); //( k is my var which gets from messagedetail model)
How can ı reach messageId over MessadeDetailModel
There is no current link between your two models that would represent a Foreign Key.
You'd need to do something like this for your model if you want a Foreign Key to link to the related object:
public class MessageDetailModel
{
[Key]
public int messageDetailsId { get; set; }
[ForeignKey("messageId")] // Added Data Annotation for the Foreign Key relationship
public MessageModel messageModel { get; set; }
public string detail { get; set; }
public int senderId { get; set; }
public int customerId { get; set; }
public string phone { get; set; }
public DateTime date { get; set; }
public int messageId { get; set; } // This would be your Foreign Key
}
I've added the messageId column to your MessageDetailModel to match the Primary Key column of your MessageModel as that's necessary for the link to form.
You would use the [ForeignKey("messageId")] Data Annotation above the variable for the MessageModel to determine what value it needs to use when finding the object you want.

EF CORE 2.0 Incompatible relationship (nullable foreign key)

In our businessslogic we have some contacts row that may have a relationship with one billing row (0..N).
Here the contact class
public class ESUsersContact
{
[Key]
public int Id { get; set; }
[ForeignKey("Billing")]
public int? BillingId { get; set; }
public string Title { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string Email { get; set; }
public string City { get; set; }
public string PostalCode { get; set; }
public string Phone { get; set; }
public string CellPhone { get; set; }
public string Fax { get; set; }
public ES.Enums.BusinessESCommon.Language.AllLanguage Language { get; set; }
public virtual ICollection<ESUsersCompany> Companies { get; set; }
public virtual ESUsersBilling Billing { get; set; }
}
Here is the billing class
[Key, Column(Order = 0)]
[ForeignKey("Company")]
public int CompanyId { get; set; }
[Key, Column(Order = 1)]
public ES.Enums.BusinessESUsers.Billing.Type Type { get; set; }
public ES.Enums.BusinessESUsers.Billing.Payment PaymentType { get; set; }
public ES.Enums.BusinessESUsers.Billing.Frequency PaymentFrequency { get; set; }
public decimal Amount { get; set; }
public bool IsFreeTrial { get; set; }
public DateTime FreeTrialEndDate { get; set; }
public DateTime? NextPaymentDate { get; set; }
public virtual ESUsersCompany Company { get; set; }
public virtual ICollection<ESUsersContact> Contacts { get; set; }
}
However, I receive this error doing so.
The relationship from 'ESUsersContact.Billing' to 'ESUsersBilling.Contacts' with foreign key properties {'BillingId' : Nullable<int>} cannot target the primary key {'CompanyId' : int, 'Type' : Type} because it is not compatible. Configure a principal key or a set of compatible foreign key properties for this relationship.
I don't understand why the error occurs and state the primary key {'CompanyId' : int, 'Type' : Type}.
ESUsersContact.Billing class has a composite key. ESUsersContact has to map both of the foreign keys. CompanyId and Type. You can not refer only one column since ESUsersContact.Billing has two columns for the key.

How to set one foreign key references multiple primary keys in EF

I use code-first approach. I want to use just ObjectId property in ObjectScore as foreign key for three relations with Professor (Id) , College (Id) and EducationalGroup (Id), like what's happening at SQL
CONSTRAINT [FK_ObjectScore_Colege] FOREIGN KEY([ObjectId])
CONSTRAINT [FK_ObjectScore_Professer] FOREIGN KEY([ObjectId])
CONSTRAINT [FK_ObjectScore_EducationGroup] FOREIGN KEY([ObjectId])
How to make this relation in Entity Framework (data annotations or fluent api)?
Thanks all
public class Professor : Person
{
public int ProfessorCode { get; set; }
public virtual ICollection<EducationalGroup> EducationalGroups { get; set; }
public virtual ICollection<College> Colleges { get; set; }
public virtual ICollection<ObjectScore> ObjectScores { get; set; }
}
public class College : BaseClass
{
public int CollegeCode { get; set; }
public virtual ICollection<Professor> Professors { get; set; }
public virtual ICollection<EducationalGroup> EducationalGroups { get; set; }
public virtual ICollection<ObjectScore> ObjectScores { get; set; }
}
public class EducationalGroup : BaseClass
{
public int CollegeCode { get; set; }
public virtual ICollection<Professor> Professors { get; set; }
public virtual College College { get; set; }
public virtual ICollection<ObjectScore> ObjectScores { get; set; }
}
public class ObjectScore
{
public Guid Id { get; set; }
public int CurrentScore { get; set; }
public virtual Term Term { get; set; }
public virtual Score Score { get; set; }
public int ObjectId { get; set; }
}
and my BaseClass and Person classes:
public class Person : BaseClass
{
public string Family { get; set; }
}
public class BaseClass
{
public BaseClass()
{
IsActive = false;
}
public int Id { get; set; }
public string Name { get; set; }
public DateTime? CreationDate { get; set; }
public DateTime? LastModifiedDate { get; set; }
public bool IsActive { get; set; }
}

How to create a history model of a specific model on MVC 4

I'm still new in creating Models using Entity Framework and MVC 4 Razor. I'm having a problem on how can I save a history of a model. How can I create a model that have a history on specific tables or fields ? For ex: If I wish to create a history on the changes on the school. Its still not clear to me how will I I create the model that saves history. How will be the triggering do I have to execute the save function on different models with the same data ?
Thank you so much in advance.
If anyone could be a simple example of model and a model history and how it is functioning, I'll be very grateful. Like a Sales or sales history.
Here's my code
One To Many
public class Child
{
[Key]
public int ChildID { get; set; }
[Required,Display(Name="Project Code")]
public string ProjectCode { get; set; }
public string Status { get; set; }
[DataType(DataType.Date)]
public DateTime StatusDate { get; set; }
public string FamilyName { get; set; }
public string GivenName { get; set; }
public string MiddleName { get; set; }
[DataType(DataType.Date)]
public DateTime Birthdate { get; set; }
public string Gender {get;set;}
public string Address { get; set; }
public string Section { get; set; }
public int SchoolLevelID { get; set; }
public int SchoolYearID { get; set; }
public int AreaID { get; set; }
public int SchoolID { get; set; }
public int GradeLevelID { get; set; }
//Foreign Key - One to Many
public virtual SchoolLevel SchoolLevel { get; set; }
public virtual SchoolYear SchoolYear { get; set; }
public virtual Area Area { get; set; }
public virtual School School { get; set; }
public virtual GradeLevel GradeLevel{get;set;}
//Child is foreign key at the table
public virtual ICollection<Guardian> Guardians { get; set; }
}
public class SchoolLevel
{
public int SchoolLevelID { get; set; }
public string SchoolLevelName { get; set; }
public virtual ICollection<Child> Children { get; set; }
}
public class SchoolYear
{
public int SchoolYearID { get; set; }
public string SchoolYearName { get; set; }
public virtual ICollection<Child> Children{get;set;}
}
public class Area
{
public int AreaID{get;set;}
public string AreaName { get; set; }
public virtual ICollection<Child> Children{get;set;}
}
public class School
{
public int SchoolID { get; set; }
public string SchoolName{get;set;}
public virtual ICollection<Child> Children { get; set; }
}
public class GradeLevel
{
public int GradeLevelID{get;set;}
public string GradeLevelName { get; set; }
public virtual ICollection<Child> Children { get; set; }
}
public class ChildDbContext : DbContext
{
public DbSet<Child> Children { get; set; }
public DbSet<SchoolLevel> SchoolLevels { get; set; }
public DbSet<SchoolYear> SchoolYears { get; set; }
public DbSet<Area> Areas { get; set; }
public DbSet<School> Schools { get; set; }
public DbSet<GradeLevel> GradeLevels { get; set; }
public DbSet<Guardian> Guardians { get; set; }
}
You can use this approach: Create a History model. That contains 1 changeness like o log.
public class History
{
public int HistoryId { get; set; }
public int ModelType { get; set; } //it is ModelTypeEnum value.
public int ModelId { get; set; }
public string PropertyName { get; set; }
public string Propertyvalue {get;set;}
public DateTime ChangeDate { get; set; }
public int ChangedUserId { get; set; }
}
And Enum:
public enum ModelTypeEnum
{
Child =1,
SchoolLevel = 2,
//etc..
};
For example, when you edit 1 Child entity, give changed properties name and value, it's id, type and others (ChangeDate, ChangedUserId) to History and save histories. If 3 properties will change you should save 3 history entities. Then, you can load (filter) histories by ModelId, by ChangedUserId etc.