Shortly, I want to create composite keys on my table remaining with the primary key in order to improve sql server search performance. The performance issue occurs on 200k data table whenever I search an entity without primary key (i.e a string of GUID). Assume that I have 3 classes
public class Device{
public int ID { get; set; }
public string UDID { get; set; }
public string ApplicationKey { get; set; }
public string PlatformKey { get; set; }
public ICollection<NotificationMessageDevice> DeviceMessages { get; set; }
}
public class NotificationMessageDevice {
[Column(Order = 0), Key, ForeignKey("NotificationMessage")]
public int NotificationMessage_ID { get; set; }
[Column(Order = 1), Key, ForeignKey("Device")]
public int Device_ID { get; set; }
public virtual Device Device { get; set; }
public virtual NotificationMessage NotificationMessage { get; set; }
}
public class NotificationMessage {
public int ID { get; set; }
public string Text { get; set; }
public DateTime CreateDate { get; set; }
}
modelBuilder.Entity<Device>().HasKey(t => new { t.ID, t.ApplicationKey, t.PlatformKey, t.UDID });
What the problem is that whenever I want to make ID , UDID , ApplicationKey and PlatformKey define as a Composite Key with modelBuilder it gives the following error.
NotificationMessageDevice_Device_Target_NotificationMessageDevice_Device_Source:
: The number of properties in the Dependent and Principal Roles in a
relationship constraint must be identical
I think the problem is because the navigation property on NotificationMessageDevice is not able to recognize what the primary key is on Device table. How can I resolve this problem? In addition to this I will be glad if you share your experiences improving the search performance on Entity framework. Usually the performance issue occurs on whenever I use First method without primary keys.
If Device table has composite primary key, then you need same composite foreign key on your NotificationMessageDevice table. How would SQL find Device without full primary key? Also you should make these fields to be part of NotificationMessageDevice table primary key. Otherwise you can't guarantee primary key will be unique:
public class NotificationMessageDevice
{
[Column(Order = 0), Key, ForeignKey("NotificationMessage")]
public int NotificationMessage_ID { get; set; }
[Column(Order = 1), Key, ForeignKey("Device")]
public int Device_ID { get; set; }
[Column(Order = 2), Key, ForeignKey("Device")]
public string Device_UDID { get; set; }
[Column(Order = 3), Key, ForeignKey("Device")]
public string Device_ApplicationKey { get; set; }
public virtual Device Device { get; set; }
public virtual NotificationMessage NotificationMessage { get; set; }
}
Related
So I try to create some ASP.NET project with EF Core.
I want to set propert of one entity as primary key and foreign key to another entity. The relationship is 0..1 - 1. I use DataAnnotations:
public class OfficeAssignment
{
[Key, ForeignKey("InstructorID")]
public int InstructorID { get; set; }
public Instructor Instructor { get; set; }
public string Location { get; set; }
}
But I keep getting column InstructorID as PK and InstructorID1 as FK... Any ideas, why EF behaves like that and how can I achieve my goal?
You should follow convention over configuration as much as you can. An OfficeAssignment entity should have an OfficeAssignmentId PK, like this:
public class OfficeAssignment
{
public int OfficeAssignmentId { get; set; }
//Notice that Id does not have an uppercase D
public int InstructorId { get; set; }
public string Location { get; set; }
public Instructor Instructor { get; set; }
}
However, if you don't want to follow normal conventions, the name of the property that goes in the ForeignKey attribute is the opposite of where it's declared:
public class OfficeAssignment
{
[Key, ForeignKey("Instructor")]
public int InstructorId { get; set; }
public string Location { get; set; }
public Instructor Instructor { get; set; }
}
And, if you want to keep it compile-time safe:
public class OfficeAssignment
{
[Key, ForeignKey(nameof(Instructor))]
public int InstructorId { get; set; }
public string Location { get; set; }
public Instructor Instructor { get; set; }
}
It's enough to set primary key attribute([Key]) in the OfficeAssignment class and in Instructor class we need to set such attribute:
[InverseProperty("Instructor")]
on collection of CourseAssignments. That will work as desired.
I am aware this may be a duplicate question, but I've tried using the answers provided to similar questions and I've not had any success.
The situation is as follows: I'm creating a virtual bank for a school project and in the first prototype I simply want an Account table and a Transactions table. The relation between Transaction and Account is that every Transaction references two Accounts (From and To) and Account has 0...n Transactions.
The code I've been using:
public class Transaction
{
[Column(Order = 0), Key, ForeignKey("From")]
public int FromID { get; set; }
[Column(Order = 1), Key, ForeignKey("To")]
public int ToID { get; set; }
public float Amount { get; set; }
public virtual Account From { get; set; }
public virtual Account To { get; set; }
}
public class Account
{
public int ID { get; set; }
[Required]
public String Email { get; set; }
[Required]
public float Balance { get; set; }
[InverseProperty("From")]
public virtual ICollection<Transaction> FromTransactions { get; set; }
[InverseProperty("To")]
public virtual ICollection<Transaction> ToTransactions { get; set; }
}
I have used [Column(Order = 0)] and [Column(Order = 1)] which should have resolved the problem, but VS still shows the message:
Unable to retrieve metadata for 'Bank_API.Models.Account'. Unable to
determine the composite primary key ordering for type
'Bank_API.Models.Transactions'. Use the ColumnAttribute or the HasKey
method to specify an order for composite primary keys.
This is my first time using ASP.NET or EF, so please be gentle.
P.S. I'm using .NET 4.6.1 and EF 5.
Your problem is that you have different type of key in Transaction and Account. Try to change to:
public class Account
{
public int ID { get; set; }
}
You can also make Fluent API to know that you want composite key like that:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Transaction>().HasKey(x => new { x.FromID, x.ToID });
}
This override method should be in your DbContext class.
Also Attribute ForeignKey should be up of your virtual Account not Key like you do:
public class Transaction
{
[Column(Order = 0), Key]
public int FromID { get; set; }
[Column(Order = 1), Key]
public int ToID { get; set; }
public float Amount { get; set; }
[ForeignKey("FromID")]
public virtual Account From { get; set; }
[ForeignKey("ToID")]
public virtual Account To { get; set; }
}
So i am trying to create a table with a foreign key, but it always says that it cannot find the foreign key. heres the code:
public class Tecnologies
{
[Key]
public int TecId { get; set; }
[Required]
public String Name { get; set; }
}
this one works, then i try to create this one:
public class UserTecnologies
{
[Key]
public int UserTecId { get; set; }
[ForeignKey("Id")]
public UserProfile User { get; set; }
[ForeignKey("TecId")]
public virtual Tecnologies Tecnology { get; set; }
[Required]
public int Rating { get; set; }
}
and it gives me the error :
The ForeignKeyAttribute on property 'Tecnology' on type 'ESW_CloddOffice.Models.UserTecnologies' is not valid. The foreign key name 'TecId' was not found on the dependent type 'ESW_CloddOffice.Models.UserTecnologies'. The Name value should be a comma separated list of foreign key property names.
The names are correct, what am i missing ?
Okay, i found what i was doing wrong. Heres the correct code:
public class UserTecnologies
{
[Key]
public int UserTecId { get; set; }
[ForeignKey("UserProfile")]
public virtual int UserProfileId { get; set; }
[ForeignKey("Tecnology")]
public virtual int TecnologyId { get; set; }
public virtual Tecnologies Tecnology { get; set; }
public virtual UserProfile UserProfile { get; set; }
[Required]
public int Rating { get; set; }
}
Was creating the foreign key the wrong way .
The ForeignKey attribute requires that an actual property on the entity match the name you pass in. It doesn't just tell EF what to call the key at the database level.
You either need to actually add a TecId property:
public int TecId { get; set; }
Or use fluent configuration, instead:
modelBuilder.Entity<UserTechnologies>()
.HasRequired(c => c.Technology)
.WithMany()
.Map(m => m.MapKey("TecId"));
I've got the following domain models (pseudo):
public class Camera {
public int Id { get; set; }
}
public class Display {
public int Id { get; set; }
}
public class SetupGroup {
public int Id { get; set; }
public virtual ICollection<CameraDisplayMap> Mappings { get; set; }
}
public class CameraDisplayMap {
public int Id { get; set; }
public Camera Camera { get; set; }
public Display Display { get; set; }
}
which should get mapped the following way:
[Cameras]
Id (primary key)
[Displays]
Id (primary key)
[SetupGroup]
Id (primary key)
[CameraDisplayMap]
Id (foreign key to [SetupGroup]
Camera (foreign key to [Cameras])
Display (foreign key to [Display])
I am aware the data model is not ideal, but it's a requirement in order to support one of our legacy applications which handled most mapping etc. with application logic.
Currently, I'm unable to configure this mapping with the given relationship instructions from EF Code First Fluent Configuration API, or at least I'm not sure how to do it. I tried mapping beginning from SetupGroup using WithMany, but here I can't declare that Camera and Display should be mapped on the CameraDisplayMap. Starting from CameraDisplayMap, I'm unable to declare the Id as being a foreign key to SetupGroup. Am I missing something?
CameraDisplayMap Class should be like following.
public class CameraDisplayMap {
public int Id { get; set; } //primary key
public int? SetupGroupId { get; set; } //foreign key to [SetupGroup]
public int? CameraId { get; set; } //foreign key to [Camera]
public int? DisplayId Displays { get; set; } //foreign key to [Display]
public virtual SetupGroup SetupGroups { get; set; }
public virtual Camera Cameras { get; set; }
public virtual Display Displays { get; set; }
}
I am new to Entity Framework so I don't know much about it. Currently I am working on My College Project, in that Project I came across a problem where I have two foreign keys refers to the Same column in another table. how can I handle this situation.
Is it necessary to create Navigation Property for Every Foreign key. And if I create another Navigaton property for ContactId then it is necessary to create another Navigation Property in User class like:
public virtual ICollection<BlockedUser> SomePropertyName { get; set; }
please tell me the best way to overcome this problem. I am using Entity Framework 6.
Here are My Model Classes:
public class BlockedUser
{
// User Foreign Key
public int UserId { get; set; } // Composite Primary Key
// User Foreign key
public int ContactId { get; set; } // Composite Primary Key
// User Navigation Property
public virtual User User { get; set; }
}
public class User
{
public int UserId { get; set; } // Primary key
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
// BlockedUser Navigation Property
public virtual ICollection<BlockedUser> BlockedUsers { get; set; }
}
Is it necessary to create Navigation Property for Every Foreign key?
Yes, or more precisely: You need at least one navigation property for every relationship. "At least one" means that you can decide which of the two entities you want to add the navigation property to. It normally depends on the most common use cases in your application if you often want to navigate from entity A to entity B or the other way around. If you want, you can add the navigation properties to both entities but you don't need to.
In your model you apparently have two (one-to-many) relationships. If you want to expose navigation properties in both entities you would need four navigation property and - important! - you have to define which navigation properties form a pair for a relationship (see the [InverseProperty] attribute in the following code snippet).
With data annotations it would like this:
public class BlockedUser
{
[Key, ForeignKey("User"), Column(Order = 1)]
public int UserId { get; set; }
[Key, ForeignKey("Contact"), Column(Order = 2)]
public int ContactId { get; set; }
[InverseProperty("BlockedUsers")]
public virtual User User { get; set; }
[InverseProperty("BlockedContacts")]
public virtual User Contact { get; set; }
}
public class User
{
public int UserId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
public virtual ICollection<BlockedUser> BlockedUsers { get; set; }
public virtual ICollection<BlockedUser> BlockedContacts { get; set; }
}
If you don't want the BlockedContacts collection you can probably just remove it and the [InverseProperty("BlockedContacts")] attribute from the Contact navigation property as well.
You could use attribute ForeignKey to solve your problem. ForeignKey is used to pair navigation property and foreign key property.There is no difference between FK data annotation with Foreign Key property and FK with Navigation Properties. However, the following code will create two foreign keys with different name.
public class BlockedUser
{
// User Foreign Key
[ForeignKey("UserId")]
public int UserId { get; set; } // Composite Primary Key
// User Foreign key
[ForeignKey("BlockedUser_User")]
public int ContactId { get; set; } // Composite Primary Key
// User Navigation Property
public virtual User User { get; set; }
}
public class User
{
public int UserId { get; set; } // Primary key
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
// BlockedUser Navigation Property
public virtual ICollection<BlockedUser> BlockedUsers { get; set; }
}