EF 4.4 InverseProperty does not quite inverse - entity-framework

This might really be something obvious but I'm not sure why my InverseProperty annotation does not work the other way.
I have this 2 classes (simplified):
public class Cluster
{
[Key]
public int ClusterId { get; set; }
[Required]
[MaxLength(80, ErrorMessage = "DimensionCluster Name cannot be more than 80 characters in length.")]
[Display(Name = "DimensionCluster Name")]
public string ClusterName { get; set; }
[InverseProperty("DimensionCluster")]
public virtual IEnumerable<Dimension> Dimensions { get; set; }
}
public class Dimension
{
[Key]
public int DimensionId { get; set; }
[Required]
[MaxLength(80, ErrorMessage = "Dimension Name cannot be more than 80 characters in length.")]
[Display(Name = "Dimension Name")]
public string DimensionName { get; set; }
[Required]
[Display(Name = "Short Definition")]
public string ShortDefinition { get; set; }
[Required]
[Display(Name = "DimensionCluster Name")]
public int ClusterId { get; set; }
[ForeignKey("ClusterId")]
public virtual Cluster DimensionCluster { get; set; }
}
The InverseProperty annotation above does not work. I get:
The InversePropertyAttribute on property 'Dimensions' on type
'PDguide.Models.Cluster' is not valid. The property 'DimensionCluster'
is not a valid navigation property on the related type
'System.Collections.Generic.IEnumerable`1[PDguide.Models.Dimension]'.
Ensure that the property exists and is a valid reference or collection
navigation property.
Tried a lot of MSDN documents and SO answers. And I finally tried it the other way (code below), and it worked!
public class Cluster
{
[Key]
public int ClusterId { get; set; }
[Required]
[MaxLength(80, ErrorMessage = "DimensionCluster Name cannot be more than 80 characters in length.")]
[Display(Name = "DimensionCluster Name")]
public string ClusterName { get; set; }
public virtual IEnumerable<Dimension> Dimensions { get; set; }
}
public class Dimension
{
[Key]
public int DimensionId { get; set; }
[Required]
[MaxLength(80, ErrorMessage = "Dimension Name cannot be more than 80 characters in length.")]
[Display(Name = "Dimension Name")]
public string DimensionName { get; set; }
[Required]
[Display(Name = "Short Definition")]
public string ShortDefinition { get; set; }
[Required]
[Display(Name = "DimensionCluster Name")]
public int ClusterId { get; set; }
[ForeignKey("ClusterId")]
[InverseProperty("Dimensions")]
public virtual Cluster DimensionCluster { get; set; }
}
I have read somewhere (I could not find that reference now, or I may have inferred it incorrectly) that you can specify the InverserProperty annotation on either end of the relationship. But that does not seem to be the case here?
Am I right in my understanding that InverseProperty should work with either property?

You are right. In Programming Entity Framework: Code First
by Lerman and Miller it says on page 72
You can place the annotations on either end of the relationship (or both ends if you
want).
When I look in the current EF source, it seems that only collection properties of type ICollection<T> are recognized as valid inverse properties. So I think that changing the type of your Dimensions property into ICollection<Dimension> would allow you to put the InversePropertyAttribute there as well.

Related

Using Inherited Entity Class in asp.net EF Core

I have following Entity Class (Which mapped directly to table of SQL Server DB)
public class PROCESSCARD : BaseClass
{
[Key]
[Display(Name = "Card No")]
public String ProcessCardID { get; set; }
[Display(Name = "Entry Date")]
public DateTime EntryDate { get; set; }
[Display(Name ="Job Type")]
public String JobType { get; set; }
[Display(Name = "Job / Non Job")]
public String JobNonJob { get; set; }
[Display (Name = "Cost Booking")]
public String CostBooking { get; set; }
[Display(Name = "Planned Hrs/Qty")]
public Decimal? PlannedHours { get; set; }
}
Above class inherits from BaseClass which is as follow
public class BaseClass
{
[NotMapped]
public String StatusMessage { get; set; }
}
Now upto this there is no issue everything is just fine,
but I am storing deleted data of entity PROCESSCARD to PROCESSCARD_HIST, and I want to show deleted history data to user.
Structures of both entity (PROCESSCARD and PROCESSCARD_HIST are ditto same) so I created another entity class PROCESSCARD_HIST, and to avoid duplicate members, I inherited PROCESSCARD_HIST from PROCESSCARD,
public class PROCESS_CARD_HIST : PROCESS_CARD
{
}
but now when I try to access data from PROCESSCARD_HIST class, it throws error like "Invalid column name 'Discriminator'",
Any Idea how I can achieve this?
If you don't want to repeat the properties in both classes, introduce another unmapped superclass
public class ProcessCardBase : BaseClass
{
[Key]
[Display(Name = "Card No")]
public String ProcessCardID { get; set; }
[Display(Name = "Entry Date")]
public DateTime EntryDate { get; set; }
[Display(Name ="Job Type")]
public String JobType { get; set; }
[Display(Name = "Job / Non Job")]
public String JobNonJob { get; set; }
[Display (Name = "Cost Booking")]
public String CostBooking { get; set; }
[Display(Name = "Planned Hrs/Qty")]
public Decimal? PlannedHours { get; set; }
}
Then
public class ProcessCard : ProcessCardBase
{
}
public class ProcessCardHistory : ProcessCardBase
{
}

.Include() method in APIController with one-to-many relations?

One display should have many media(images, videos) in my project. I'm using Entity Framework Core to build my database, and CRUD with my API Controller.
I designed my Model classes as such:
[Table("Displays")]
public class Display : ConcurrencyCheck
{
[Key]
public int Id { get; set; }
[Required(ErrorMessage = "{0} skal udfyldes!")]
[Display(Name = "Display navn")]
public string Name { get; set; }
[Display(Name = "Display tændt")]
public bool IsOn { get; set; }
[Display(Name = "Display beskrivelse")]
public string Description { get; set; }
public IEnumerable<Video> Videos { get; set; }
public IEnumerable<Image> Images { get; set; }
}
public abstract class Media : ConcurrencyCheck
{
[Key]
public int Id { get; set; }
[Required(ErrorMessage = "{0} skal udfyldes!")]
[Display(Name = "Medie navn")]
public string Name { get; set; }
[Display(Name = "Medie beskrivelse")]
public string Description { get; set; }
[Display(Name = "Medie filtype")]
public string FileType { get; set; }
[Required(ErrorMessage = "{0} skal udfyldes!")]
[Display(Name = "Medie filsti")]
public string FilePath { get; set; }
public int? DisplayId { get; set; }
[ForeignKey("DisplayId")]
public Display Display { get; set; }
}
[Table("Videos")]
public class Video : Media
{
[Display(Name = "Frames")]
public int Frames { get; set; }
[Display(Name = "Filsti på undetekster")]
public string SubtitlesPath { get; set; }
[Display(Name = "Filsti på thumbnail")]
public string ThumbnailPath { get; set; }
}
[Table("Images")]
public class Image : Media
{
}
public abstract class ConcurrencyCheck
{
[Timestamp]
public byte[] RowVersion { get; set; }
[DataType(DataType.DateTime)]
[DisplayFormat(DataFormatString = "{0:dd/MM/yyyy HH:mm}", ApplyFormatInEditMode = true)]
public DateTime CreatedDate { get; set; }
[DataType(DataType.DateTime)]
[DisplayFormat(DataFormatString = "{0:dd/MM/yyyy HH:mm}", ApplyFormatInEditMode = true)]
public DateTime? UpdatedDate { get; set; }
}
And my API controllers are scaffolded with 'API Controller with actions, using Entity Framework'.
Currently in the api-controller 'DisplaysController', I don't see the .Include(x => x.Media), though I read somewhere it's used? One display should have many media(images, videos).
Should I include it somehow somewhere, or does it do that automatically by the models I have?
scaffolded with API Controller with actions, using Entity Framework just provide the most basic five database operation methods -- select , select by id, update, add and delete. Its purpose is to help users build basic crud faster and more easily. You can add your own code on the default code template.
The default code template
Add your own code

E.F 6.0 Code first One to One Navigation Property Exception

I am issuing a very strange scenario using Code first with existing database and asp.net identity entity framework. I have a simple userprofile model
[Table("CSUserProfile")]
public partial class UserProfile
{
[Key]
public string Id { get; set; }
[Required]
[Display(Name = "FirstName")]
public string FirstName { get; set; }
[Required]
[Display(Name = "LastName")]
public string LastName { get; set; }
[Required]
[Display(Name = "Phone")]
public string Phone { get; set; }
[Required]
public string Email { get; set; }
[Required]
[Display(Name = "Location")]
public string Location { get; set; }
[Required]
[Display(Name = "HomeTown")]
public string Hometown { get; set; }
public byte[] BlobData { get; set; }
[ForeignKey("fPersonLinkGID")]
public virtual List<ProfilePic> ProfilePic { get; set; }
}
and an image profile pic
[Table("CSProfilePic")]
public partial class ProfilePic
{
[Key]
public Guid? GID { get; set; }
public string fPersonLinkGID { get; set; }
public byte[] BlobData { get; set; }
}
the foreign key is the fPersonLinkGID. everything works fine but my problem is that if i want an one-to-one relation between the userprofile and the image like this
public virtual ProfilePic ProfilePic { get; set; }
(which is the correct scenario) I am getting this strange exception :
The ForeignKeyAttribute on property 'ProfilePic' on type 'eUni.Model.Application.UserProfile' is not valid. The foreign key name 'fPersonLinkGID' was not found on the dependent type 'eUni.Model.Application.UserProfile'. The Name value should be a comma separated list of foreign key property names.
I can not understand why I am getting that exception
You could read this answer. It introduces how to configure one to one relationship by HasRequired and WithOptional.
As for me, I will create one to one relationship by following way.
public class Store {
[Key]
public long Id { get; set; }
public virtual Item TheItem { get; set; }
// ....
}
public class Item {
// It is FK, and also PK.
[Key, ForeignKey("TheStore")]
public long Id { get; set; }
// The same string in the ForeignKey attribute. Ex: ForeignKey("TheStore")
public virtual Store TheStore { get; set; }
// ....
}

Multiplicity not allowed. Entity Framework

I am attempting to use MVC4 for the first time and am receiving the following error when I try to create a controller? Could someone kindly steer me in the right direction?
Microsoft Visual Studio
System.Data.Entity.Edm.EdmAssociationEnd: : Multiplicity is not valid
in Role 'PropertyData_DNISData_Target' in relationship
'PropertyData_DNISData'. Because the Dependent Role properties are not
the key properties, the upper bound of the multiplicity of the
Dependent Role must be '*'.
public class PropertyData
{
[Key]
public virtual string PropertyID { get; set; }
[ForeignKey ("DNISData")]
public virtual string DNIS { get; set; }
public virtual string PropertyName { get; set; }
public virtual string PropertyGreeting { get; set; }
public virtual string PropertyOperator { get; set; }
public virtual string InvalidEntryPrompt { get; set; }
public virtual string NoEntryPrompt { get; set; }
public virtual string Comment { get; set; }
public virtual DNISData DNISData { get; set; }
}
public class DNISData
{
[Key]
public virtual string DNIS { get; set; }
[ForeignKey("PropertyData")]
public string PropertyID { get; set; }
public virtual string VDN { get; set; }
public virtual string PropertyGreeting { get; set; }
public virtual string Comment { get; set; }
public virtual PropertyData PropertyData { get; set; }
}
public class DigitData
{
[ForeignKey ("DNISData")]
[Key]
public virtual string DNIS { get; set; }
[Key]
public virtual string Digit { get; set; }
public virtual string InvalidEntryPrompt { get; set; }
public virtual DNISData DNISData { get; set; }
}
You have a 1 to 1 relationship between PropertyData and DNISData. This can only be done via shared primarykey in EntityFramework.
This question can give you the anwser you are looking for:
How to declare one to one relationship using Entity Framework 4 Code First (POCO)

Entity Framework/MVC4 - Relation with multiple column key

I am new to EF and am having trouble figuring how to set up relationship between my main table Investors, with contact information, and a table Notes which can have many notes per investor. Here are the models:
public class Investor
{
public int Id { get; set; }
public string Name { get; set; }
public string Company { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
public string Cell { get; set; }
public string Fax { get; set; }
[Display(Name="Address 1")]
public string Address1 { get; set; }
[Display(Name = "Address 2")]
public string Address2 { get; set; }
public string City { get; set; }
[StringLength(2, ErrorMessage = "State must be 2 characters")]
public string State { get; set; }
public string Zip { get; set; }
public string ContactTableId { get; set; }
[ForeignKey("ContactTableId, ContactId")]
public virtual List<Note> Notes { get; set; }
}
public class Note
{
[Key]
[Column(Order = 0)]
public string ContactTableId { get; set; }
[Key]
[Column(Order = 1)]
public int? ContactId { get; set; }
public string note { get; set; }
public DateTime? DateCreated { get; set; }
}
My attempt as setting this up, as above, generated the error 'The number of properties in the Dependent and Principal Roles in a relationship constraint must be identical.' on the statement:
public ActionResult Index()
{
return View(db.Investors.ToList());
}
in the controller. How do I set this up to make it pull the Notes automagically.
The foreign key is not "ContactTableId, ContactId", it is the single field Investor_Id in table Note (or Notes). EF thinks you try to map the single key to two field and coins this somewhat elusive exception message. But just remove the ForeignKey attribute and EF will use the foreign key field in Note.