As a new programmer I am trying to understand when I should create navigation properties for my Models. What are the trade offs?
On the extremes, the model can just contain ever field need, or the base model can have navigation properties for every field?
Or should navigation property only be used for complex related entities (an entity with more than one property)?
Another consideration I am considering is what works best for MVC drop down or jquery autocomplete. How will designing the model impact application and sql performance?
public class Vendor
{
public int ID { get; set; }
public string Name { get; set; }
public string Number { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
public string PostalCode { get; set; }
public string Country { get; set; }
}
or I could do this and assume the related tables also exists in the namespace and in turn the database.
public class Vendor
{
public int ID { get; set; }
public virtual Name Name { get; set; }
public virtual Number Number { get; set; }
public virtual Street Street { get; set; }
public virtual City City { get; set; }
public virtual State State { get; set; }
public virtual PostalCode PostalCode { get; set; }
public virtual Country Country { get; set; }
}
I can see that some of the related entities will be static in nature like States but Number and Street will grow over time.
If your property can be represented by a simple database column, then you use the first approach, if you property itself has its own properties, then you will need a navigational property. If your case, if the City also has properties such as Id, Name, etc, then you will use the navigation property, however, if you only want to store city as the name, your first approach will work.
Related
i am trying to define a database model in code-first to see and display which user is assigned as a specialist for the record data.
I have a very simple model for the user:
public class User
{
public int ID { get; set; }
public string userName { get; set; }
public string firstName { get; set; }
public string lastName { get; set; }
....
}
Next I have defined two (simple) models which define the data that can be edited by the user and the specialist should be assigned to using a dropdownlist:
public class Order
{
public int ID { get; set; }
public string orderNumber { get; set; }
public int specialistID { get; set; }
public virtual User specialist{ get; set; }
}
public class Part
{
public int ID { get; set; }
public string partNumber { get; set; }
public string description { get; set; }
public int specialistID { get; set; }
public virtual User specialist{ get; set; }
}
What kind of relation between the models can be used without having a navigation property for each table in the User model?
Do I need to use additional tables to define the relationship: User.Id-Order.specialistID and the relationship: User.Id-Part.specialistID ?
Is there a smarter way out-of-the-box by Entity Framework?
Many thanks for your answers.
Pascal
By default when you add forign-key constraint to the many-to-one table the Entity Framework add virtual property to the entity class and virtual ICollection to the User.
I am new to MVC and was trying to get the Scaffolding to automagically create the drop down list in the PersonTitle for Person and Title. I got the drop down list to work however, the scaffolding function takes the first instance of a string as the value of the drop down. As in the case of the Person, the first name is used. However, that is not very informative.
I want to be able to modified it to contain the First and Last name. What is the best solution for this? I tried adding a FullName field but that has its own set of problems. Once of them being, I don't want the program/user to handle extra data entries.
Is there a better method of creating the drop down list for Person and Title after the scaffolding completes? What is the best way to add foreign key drop down list from other tables?
It would help if you provide code samples as I am new to MVC and the best practices solution as I would have to do this to several other tables.
Thanks much.
A person can have many titles
// Title -->>PersonTitle<<<----Person
public class PersonTitle
{
//person can have many titles
public int PersonTitleID { get; set; }
public int PersonID { get; set; }
public int TitleID { get; set; }
public virtual Person Person { get; set; }
public virtual Title Title { get; set; }
}
List of Titles
public class Title
{
public int TitleID { get; set; }
[Display(Name = "Title Name")]
public string TitleName { get; set; } //drop down text
public virtual ICollection<PersonTitle> PersonTitles { get; set; }
}
List of People
public class Person
{
public int PersonID { get; set; }
public string FirstName { get; set; } //drop down text is used
public string LastName { get; set; }
public virtual ICollection<PersonTitle> PersonTitles { get; set; }
}
I have a Code First MVC 4 Web app - there's a many to many relationship between Places:
public virtual int PlaceID { get; set; }
public virtual string Name { get; set; }
public virtual ICollection<User> Followers { get; set; }
and Users:
public virtual int UserID { get; set; }
public virtual string Name { get; set; }
public virtual ICollection<Place> Places { get; set; }
Users can 'follow' many places, places can have many followers.
I would like to store additional information about the relationship - say a rating. So a user could have a rating for each place they follow, of between 1-10, say.
How can I achieve that - including CRUD operations (Code First, Entity Framework 5).
Thanks.
You will need to replace the many-to-many with two one-to-many relationships to an intermediate class that has the rating property which could be defined as below (you may need to add navigation attributes):
Create an intermediate class
public class UserPlaceRelationship {
public virtual int PlaceID { get; set; }
public virtual int UserID { get; set; }
public virtual Place Place { get; set; }
public virtual User User { get; set; }
public virtual int Rating { get; set; }
}
Update your places class:
public virtual int PlaceID { get; set; }
public virtual string Name { get; set; }
public virtual ICollection<UserPlaceReationship> UserRelationships { get; set; }
and your users class:
public virtual int UserID { get; set; }
public virtual string Name { get; set; }
public virtual ICollection<UserPlaceReationship> PlaceRelationships { get; set; }
Querying will be a little trickier as you will have to now navigate through the intermediate class.
You must create a junction table and add extra info to it.
Till now, there is no way to create a CRUD master-detail controller with related views.
You should follow the answer I provided to this question of yours...
I'm trying to create a model that can optionally refer to a parent of the same type, for example:
public class Category
{
public virtual long CategoryID { get; set; }
public virtual Category? ParentCategory { get; set; }
public virtual int UserID { get; set; }
public virtual string Name { get; set; }
}
As you can see there is an optional member called ParentCategory that is optional and refers to a class of type Category (i.e. the same type). As I'm sure you can guess, I'm trying to create a simple Category tree, where the root node(s) will not have a parent.
This results in the following error when the Entity Framework tries to create the database:
"The ForeignKeyAttribute on property 'ParentCategoryID' on type 'MyProject.Models.Category' is not valid. The navigation property 'Category' was not found on the dependent type 'MyProject.Models.Category'. The Name value should be a valid navigation property name."
I also tried this:
public class Category
{
public virtual long CategoryID { get; set; }
[ForeignKey("Category")]
public virtual long? ParentCategoryID { get; set; }
public virtual int UserID { get; set; }
public virtual string Name { get; set; }
}
But again this resulted in the same error.
Is it possible to model this using EF Code First? Its easy to model it int he database if I were to create the database manually.
Thanks in advance
Ben
Your first example wouldn't even compile because T?, a shortcut for Nullable<T> can only be applied to value types.
The following works fine here:
public class Category
{
public virtual long CategoryID { get; set; }
public virtual Category ParentCategory { get; set; }
}
Now, this will use an ugly name by default for the FK, ParentCategory_CategoryID.
This is a way to get a nicer name, plus some flexibility when using it:
public class Category
{
public virtual long CategoryID { get; set; }
[ForeignKey("ParentCategoryID")]
public virtual Category ParentCategory { get; set; }
public virtual long? ParentCategoryID { get; set; }
}
I am building a reservation system. I have users in roles('admin', 'client', 'employee', 'student').
Each reservation must be associated with a user of role client, it might be assigned to user of role employee and might also be assigned to user of role student.
So in my reservation class I have properties of type User and I have marked them with [ForeignKey("AnytypeId")] attribute to hint EF for relations.
I have seen code like this at http://blog.stevensanderson.com/2011/01/28/mvcscaffolding-one-to-many-relationships/
public class Reservation
{
public int ReservationID
{
get;
set;
}
[Required(ErrorMessage="Please provide a valid date")]
public DateTime ReservationDate
{
get;
set;
}
public DateTime ReservationEnd { get; set; }
public DateTime EntryDate
{
get;
set;
}
public DateTime UpdatedOn
{
get;
set;
}
public decimal Ammount
{
get;
set;
}
public decimal? Discount { get; set; }
[DataType(DataType.MultilineText)]
public string ServiceDetails { get; set; }
[DataType(DataType.MultilineText)]
public string Remarks { get; set; }
public String PaymentMethod { get; set; }
public string VoucherNumber { get; set; }
public int ServiceID
{
get;
set;
}
public virtual Service Service
{
get;
set;
}
public string EmployeeID { get; set; }
[ForeignKey("EmployeeID")]
public virtual User Employee { get; set; }
public string ClientID { get; set; }
[ForeignKey("ClientID")]
public virtual User Client { get; set; }
public string StudentID { get; set; }
[ForeignKey("StudentID")]
public virtual User Student { get; set; }
}
public class ReservationMap : EntityTypeConfiguration<Reservation>
{
public ReservationMap()
{
this.HasOptional(r => r.Client).WithMany().WillCascadeOnDelete(true);
this.HasOptional(r => r.Employee).WithMany().WillCascadeOnDelete(false);
this.HasOptional(r=>r.Student).WithMany().WillCascadeOnDelete(false);
}
}
Now as I run my mvc3 EF code first app database created for me on the fly with following ERD and edmx model.
Now few problems that I am having:
1. When I am listing all the users of role clients in view their reservation property is showing always 0 even if their are reservations available in database. I don't know why this collection property marked with virtual is not loading??
Please I am stuck with this help me out here this is the last thing remaining.
There are couple of problems in your model. You have configured the one to many relationship in such a way that the many end(Reservations property) is excluded from the mapping. Hence the Reservations will not be loaded by EF.
The other problem is if you are going to map the Reservations property as the many end of the relationship, what will be the navigational property? is it Employee, Client, Student? Because only one of these properties can participate in the relationship with Reservations property.
It is not clear as to how these relationships should be modeled by your description. One way would be to have 3 collection properties.
public class ReservationMap : EntityTypeConfiguration<Reservation>
{
public ReservationMap()
{
HasOptional(r => r.Client).WithMany(u => u.ClientReservations).WillCascadeOnDelete(true);
HasOptional(r => r.Employee).WithMany(u => u.EmployeeReservations).WillCascadeOnDelete(false);
HasOptional(r=>r.Student).WithMany(u => u.StudentReservations).WillCascadeOnDelete(false);
}
}