Entity Framework 6 foreign key - database

I am coding an MVC5 internet application with EF6, and have a question in regards to a foreign key name.
I have a model called MapLocationList that has these two fields:
public int mapLocationListGalleryId { get; set; }
public virtual MapLocationListGallery mapLocationListGallery { get; set; }
When EF creates the table, there is both the following columns:
mapLocationListGalleryId
MapLocationListGallery_Id
Can someone please explain why there are two columns for the MapLocationListGallery foreign key?
Thanks in advance
EDIT
I have changed the name to use an uppercase M, yet the additional column is still there.
Here is my model:
public class MapLocationList : IMapLocationItemWithAssets
{
[Key]
public int Id { get; set; }
[Required]
public string name { get; set; }
public bool enabled { get; set; }
[ScaffoldColumn(false)]
public string mapLocationItemType { get; set; }
[ScaffoldColumn(false)]
public string userName { get; set; }
[ScaffoldColumn(false)]
public DateTime creationDate { get; set; }
[ScaffoldColumn(false)]
public DateTime lastUpdate { get; set; }
public string thumbnailDisplayText { get; set; }
public bool parentIsMapLocation { get; set; }
public int thumbnailAssetId { get; set; }
public virtual Asset thumbnailAsset { get; set; }
public int mapLocationId { get; set; }
public virtual MapLocation mapLocation { get; set; }
public int mapLocationListGalleryId { get; set; }
public virtual MapLocationListGallery mapLocationListGallery { get; set; }
public virtual ICollection<MapLocationListItem> listItems { get; set; }
public MapLocationList()
{
creationDate = DateTime.Now;
lastUpdate = DateTime.Now;
listItems = new List<MapLocationListItem>();
}
}
I also have the following in the OnModelCreating function:
modelBuilder.Entity<MapLocationListGallery>()
.HasRequired(c => c.thumbnailAsset)
.WithMany()
.WillCascadeOnDelete(false);
modelBuilder.Entity<MapLocationList>()
.HasRequired(c => c.thumbnailAsset)
.WithMany()
.WillCascadeOnDelete(false);
modelBuilder.Entity<MapLocationList>()
.HasRequired(c => c.mapLocationListGallery)
.WithMany()
.WillCascadeOnDelete(false);
modelBuilder.Entity<MapLocationListItem>()
.HasRequired(c => c.thumbnailAsset)
.WithMany()
.WillCascadeOnDelete(false);

I use this approach as well and I do not experience this behavior. Probably you need to rename your properties to CamelCase (note the capital M):
public int MapLocationListGalleryId { get; set; }
public virtual MapLocationListGallery MapLocationListGallery { get; set; }
If that doesn't help take a look at the ForeignKeyAttribute here and here.
Edit
I'm not familiar with the fluent api, but I think you could try to set the foreign key explicitly using something like:
modelBuilder.Entity<MapLocationList>()
.HasRequired(c => c.mapLocationListGallery)
.WithMany()
.HasForeignKey(x => x.mapLocationListGalleryId)
.WillCascadeOnDelete(false);
For more info see this article, topic: "Configuring Unconventional Foreign Key Names". Although it's strange this is necessary because your code seems to comply with the Code First convention (with capital M, i.e. the class name).

Related

EF Core query full join between many-to-many relation

I'm working with EF core and I have a many-to-many relation between STUDENTS and SUBJECTS, like this:
public class StudentDetail
{
[Key]
[JsonPropertyName("Id")]
public int Id { get; set; }
[Required]
[Column(TypeName ="nvarchar(50)")]
[JsonPropertyName("Name")]
public string Name { get; set; }
[JsonPropertyName("StudentSubjects")]
public virtual IEnumerable<StudentSubject> StudentSubjects {get; set;}
}
public class SubjectDetail
{
[Key]
[JsonPropertyName("Id")]
public int Id { get; set; }
[Required]
[Column(TypeName = "nvarchar(20)")]
[JsonPropertyName("SubjectName")]
public string SubjectName { get; set; }
[Required]
[JsonPropertyName("Teacher")]
public virtual TeacherDetail Teacher { get; set; }
[JsonPropertyName("StudentSubjects")]
public IEnumerable<StudentSubject> StudentSubjects { get; set; }
}
public class StudentSubject
{
[JsonPropertyName("StudentId")]
public int StudentId { get; set; }
[JsonPropertyName("Student")]
public StudentDetail Student { get; set; }
[JsonPropertyName("SubjectId")]
public int SubjectId { get; set; }
[JsonPropertyName("Subject")]
public SubjectDetail Subject { get; set; }
[Required]
[Column(TypeName = "nvarchar(3)")]
[JsonPropertyName("Grade")]
public string Grade { get; set; }
}
I create my Databse using migrations, so after I did the migration, the database was created like this:
I need a query that bring me all the Subjects with their teacher and grade of an specific Student. I was tryng doing it like this:
var subjects = await _context.StudentSubject
.Include(s => s.Subject)
.Where(sid => sid.StudentId == student.Id)
.Select(st => st.Subject)
.Include(t => t.Teacher)
.ToListAsync();
But I'm getting an ERROR saying that I'm tryng to use Include(); on a non Queryable Entity. Anyone know what am I doing wrong?
Include will only work if you are having a link between two table and that is defined by keyword Virtual in C# classes. Please use public virtual ICollection instead of public IEnumerable and follow the link for more details. If you still wants to continue with same class then try using join in Linq queries.

I want to make a one-to-one relationship between two columns in ASP.NET Core

I have reading and jobOrder class. I want to create a relationship between joborderId in the jobOrder class and jobOrderId in reading class.
public class JobOrder
{
[Key]
public int Id { get; set; }
public int JobOrderId { get; set; }
public DateTime StartDate { get; set; }
public Nullable<DateTime> EndDate { get; set; }
public string MachineCode { get; set; }
public decimal TotalLength { get; set; }
}
public class Reading
{
public int Id { get; set; }
public string MachineCode { get; set; }
public decimal Length { get; set; }
public bool status { get; set; }
public DateTime time { get; set; }
public int JobOrderId { get; set; }
public JobOrder JobOrder { get; set; }
}
The best way is to take a look at the documentation: https://learn.microsoft.com/en-us/ef/core/modeling/relationships#one-to-one
If you do it the way you described then EF will choose one of the entities to be the dependent based on its ability to detect a foreign key property. If the wrong entity is chosen as the dependent, you can use the Fluent API to correct this.
When configuring the relationship with the Fluent API, you use the HasOne and WithOne methods.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne(p => p.BlogImage)
.WithOne(i => i.Blog)
.HasForeignKey<BlogImage>(b => b.BlogForeignKey);
}
If you follow the code first naming conventions EF will automatically discover the Key, ForeignKey and Navigation properties :
public class JobOrder
{
// Primary key (can be JobOrderId as well)
public int Id { get; set; }
// other fields...
// Foreign key
public int ReadingId { get; set; }
// Navigation property
public Reading Reading { get; set; }
}
public class Reading
{
// Primary key (can be ReadingId as well)
public int Id { get; set; }
// other fields...
// Foreign key
public int JobOrderId { get; set; }
// Navigation property
public JobOrder JobOrder { get; set; }
}
If you have more than one key composite keys to create the relationship, you need to manually define the keys and foreign keys:
public class JobOrder
{
[Key]
[Column(Order=1)]
public int Id { get; set; }
[Key]
[Column(Order=2)]
public int JobOrderNo { get; set; }
// other fields...
// Foreign key
public int ReadingId { get; set; }
// Navigation property
public Reading Reading { get; set; }
}
public class Reading
{
public int Id { get; set; }
// other fields...
[ForeignKey("JobOrder")]
[Column(Order=1)]
public int JobOrderId { get; set; }
[ForeignKey("JobOrder")]
[Column(Order=2)]
public int JobOrderNo { get; set; }
// Navigation property
public JobOrder JobOrder { get; set; }
}
How about going like this, it will create 1 to 1 relationship between JobOrder and Reading
public class JobOrder
{
[Key]
public int Id { get; set; }
public int JobOrderId { get; set; }
public DateTime StartDate { get; set; }
public Nullable<DateTime> EndDate { get; set; }
public string MachineCode { get; set; }
public decimal TotalLength { get; set; }
public virtual Reading Reading { get; set; }
}
public class Reading
{
[Key]
[System.ComponentModel.DataAnnotations.Schema.ForeignKey("JobOrder")]
public int Id { get; set; }
public string MachineCode { get; set; }
public decimal Length { get; set; }
public bool status { get; set; }
public DateTime time { get; set; }
public JobOrder JobOrder { get; set; }
}

Entity Framework Model Mapping With Legacy Database and Constant

I'm using EF6 over a DB that's over 15 years old. I did not make this architecture decision. All of my experience with EF has been code-first, with models I've created myself.
One of our tables has a reference table that has some info needed in selects only. These mappings will never be used for update/insert/delete.
I have two entities. My primary table:
public class QualParam
{
[Key]
public string MillId { get; set; }
[Key]
public string Qparam { get; set; }
public string ValueNum { get; set; }
public string ActiveFlag { get; set; }
public int ModifiedTimestamp { get; set; }
public int CreatedTimestamp { get; set; }
public decimal SbIncrement { get; set; }
public string QualityDesc { get; set; }
public string TypeCode { get; set; }
public QualParamHeader QualParamHeader { get; set; }
public virtual UnitMeasure UnitMeasure { get; set; }
}
and a reference table:
public class UnitMeasure
{
[Key]
public string UnitOfMeasure { get; set; }
public int ModifiedTimestamp { get; set; }
public int CreatedTimestamp { get; set; }
public string BaseUnits { get; set; }
public string UnitDesc { get; set; }
[Key]
public string TableName { get; set; }
public string RollWeightFlag { get; set; }
public string MetricFlag { get; set; }
public string MxActionCode { get; set; }
[Key]
public string TypeCode { get; set; }
public byte[] RecordVersion { get; set; }
public List<QualParam> QualParams { get; set; }
}
QualParam may have a UnitMeasure, and UnitMeasure can have many QualParams, easy, right?
In SQL the join is done thusly
SELECT *
FROM qual_params AS q
LEFT JOIN unit_measure AS u
ON u.unit_meas = q.unit_meas
AND u.table_name = 'qual_params'
AND u.type_code = q.type_code
So yes, there's a constant, the table name, and yes the keys from the source to the reference tables don't match, and aren't even enumerated in the db to begin with. Again, legacy.
Our Db context-
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new QualParamsConfiguration());
modelBuilder.Configurations.Add(new UnitMeasureConfiguration());
base.OnModelCreating(modelBuilder);
}
I'm using auto generated configs-
public QualParamConfiguration()
: this("dbo")
{
}
public QualParamConfiguration(string schema)
{
ToTable(schema + ".qual_params");
HasKey(x => new { x.MillId, x.Qparam });
Property(x => x.Qparam).HasColumnName(#"qparam").IsRequired().IsFixedLength().IsUnicode(false).HasColumnType("char").HasMaxLength(10).HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.None);
Property(x => x.ValueNum).HasColumnName(#"value_num").IsRequired().IsFixedLength().IsUnicode(false).HasColumnType("char").HasMaxLength(9);
Property(x => x.ActiveFlag).HasColumnName(#"active_flag").IsRequired().IsFixedLength().IsUnicode(false).HasColumnType("char").HasMaxLength(1);
Property(x => x.ModifiedTimestamp).HasColumnName(#"ts_modified").IsRequired().HasColumnType("int");
Property(x => x.CreatedTimestamp).HasColumnName(#"ts_create").IsRequired().HasColumnType("int");
Property(x => x.SbIncrement).HasColumnName(#"sb_increment").IsRequired().HasColumnType("decimal").HasPrecision(7, 3);
Property(x => x.QualityDesc).HasColumnName(#"quality_desc").IsRequired().IsFixedLength().IsUnicode(false).HasColumnType("char").HasMaxLength(50);
Property(x => x.MillId).HasColumnName(#"mill_id").IsRequired().IsFixedLength().IsUnicode(false).HasColumnType("char").HasMaxLength(10).HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.None);
this.HasRequired(a => a.QparamHeader).WithMany(b => b.QualParams).HasForeignKey(c => c.Qparam).WillCascadeOnDelete(false);
}
The last navigation wrote itself, for obvious reasons. Simple relationship.
This one, not so much. I'm open to everything- I'm fairly aware at this point that I'll have to create a separate model to achieve this.
The examples I've seen using .Map must be from older versions of EF, since many of the methods are not available to me. Is it even possible to achieve this relationship?

Create multiple foreign keys referes to the same table in EF code first

In my table it has two foreign keys which refers to the same table. When I do the migration(Entity Framework Code first Approach) it pops up error as,
"One or more validation errors were detected during model generation:
Dog_Sire_Target: : Multiplicity is not valid in Role 'Dog_Sire_Target' in relationship 'Dog_Sire'. Because the Dependent Role properties are not the key properties, the upper bound of the multiplicity of the Dependent Role must be '*'.".
But if I add only one foreign key it works properly. Here is my table structure.
public class Dog
{
[Key]
public int Dog_Id { get; set; }
public string Dog_Name { get; set; }
[ForeignKey("Sire")]
public int? Dog_SireId { get; set; }
[ForeignKey("Dam")]
public int? Dog_DamId { get; set; }
[ForeignKey("Dog_SireId")]
public virtual Dog Sire { get; set; }
[ForeignKey("Dog_DamId")]
public virtual Dog Dam { get; set; }
}
Try this model:
public class Dog
{
[Key]
public int DogID { get; set; }
public string DogName { get; set; }
public int? DogSireID { get; set; }
[ForeignKey("DogSireID")]
public virtual Dog DogSire { get; set; }
public int? DogDamID { get; set; }
[ForeignKey("DogDamID")]
public virtual Dog DogDam { get; set; }
[InverseProperty("DogSire")]
public virtual ICollection<Dog> DogsSires { get; set; }
[InverseProperty("DogDam")]
public virtual ICollection<Dog> DogsDams { get; set; }
}

Better way to create database for a pricing system

I need to create a price table system so I am going to create these three tables in my database.
PricingTable (ID, Name, ServiceID, Style)
PricingTablePackages (ID, PricingTable_ID, Title, Price, PricePerTime, Info, Flag, Link)
PricingTablePackagesFeatures (ID, PricingTablePackages_ID, Feature, Value, MoreInfo)
Here one PriceTable can hold more then one PricingTablePackages and one PricingTablePackage can hold more then one PricingTablePackagesFeature.
Is any way to design a better model? In a single database Table ?
I am going to create a MVC3 Model for those table so what is the best way to do this kind of DB Table in a MVC3 Model?
I would use public virtual variables for 'lazy-loading' values when you need them using Entity Framework:
(variable types may be off depending on exactly what you want for each variable)
public class PricingTablePackages
{
public int ID { get; set; }
public int PricingTableID { get; set; }
public virtual PricingTable PricingTable { get; set; }
public string Title { get; set; }
public decimal Price { get; set; }
public decimal PricePerTime { get; set; }
public string Info { get; set; }
public bool Flag { get; set; }
public string Link { get; set; }
}
public class PricingTablePackagesFeatures
{
public int ID { get; set; }
public int PricingTableID { get; set; }
public virtual PricingTable PricingTable { get; set; }
public string Feature { get; set; }
public string Value { get; set; }
public string MoreInfo { get; set; }
}
public class PricingTable
{
public int ID { get; set; }
public string Name { get; set; }
public int ServiceID { get; set; }
public virtual Service Service { get; set; } // if there is a Service class
public string Style { get; set; }
}

Resources