I am using MVC 4 with EF code first approach. I have two simple objects. These are their POCO classes:
public class Activity
{
//Primitive Properties
[HiddenInput]
public int Id { get; set; }
[Required]
public int LengthInMinutes { get; set; }
public string AdditionalInfo { get; set; }
[Required]
public bool Archive { get; set; }
//Navigation Properties
public virtual User User { get; set; }
public virtual ActivitySet ActivitySet { get; set; }
public virtual ICollection<Company> Companies { get; set; }
public virtual ICollection<Description> Descriptions { get; set; }
}
public class Company
{
//Primitive Properties
[HiddenInput]
public int Id { get; set; }
[Required]
public string Title { get; set; }
[Required]
public bool Archive { get; set; }
//Navigation Properties
public virtual ICollection<Activity> Activities { get; set; }
}
So there is a many-to-many relationship between Activity and Company entities. I am creating new Activity in my repository class, but when I assign a Company for the Activity like so:
activity.Companies.Add(company);
I get NullReference exception. I had a look around but according to this link:
BuildStarted.com
my approach seems to be right.
Why doesn't it work???
Before you can use Add() off Companies, it needs to be initialized.
activity.Companies = new List<Company>();
You could also initialize that in the contructor of Activity.
public class Activity
{
public Activity()
{
Companies = new List<Company>();
Descriptions = new List<Description>();
}
//Primitive Properties
[HiddenInput]
public int Id { get; set; }
[Required]
public int LengthInMinutes { get; set; }
public string AdditionalInfo { get; set; }
[Required]
public bool Archive { get; set; }
//Navigation Properties
public virtual User User { get; set; }
public virtual ActivitySet ActivitySet { get; set; }
public virtual ICollection<Company> Companies { get; set; }
public virtual ICollection<Description> Descriptions { get; set; }
}
Related
I have asked question in a different post, but seems that was not the right question, so going to reword here:
I have three classes:
public class StateLog : BaseModel
{
public Guid StateLogId { get; set; }
public Guid LookupMasterId { get; set; }
public Guid EntityId { get; set; }
public string Discriminator { get; set; }
public bool IsActive { get; set; }
public virtual LookupMaster State { get; set; }
}
Second class:
public class ApplicationState : StateLog
{
[Column("EntityId")]
public Guid ApplicationId { get; set; }
}
There is another Class DocumentStates which inherits from StateLog.
Application:
public class Application : BaseModel
{
public Guid ApplicationId { get; set; }
public Guid UserId { get; set; }
public virtual User User { get; set; }
[Required]
public Guid ApplicationTypeId { get; set; }
public bool? AuthorizedToWork { get; set; } = false;
public string Token { get; set; }
public string ApplicationTitle { get; set; }
public string WorkStartDate { get; set; }
public Nullable<DateTime> SignedAt { get; set; } = DateTime.Now;
public bool? Signed { get; set; }
public string Notes { get; set; }
public virtual ICollection<ApplicationSelfDeclaration> ApplicationSelfDeclarations { get; set; }
public virtual ICollection<ApplicationState> ApplicationStates { get; set; }
public virtual ICollection<StateLog> StateLogs { get; set; }
}
I am trying to save statelogs for both application and documents in same table and based on Discriminator, fetch data.
E.g.
_context.Applications.include(a => a.ApplicationState)
This is not not working. ApplicationState should Alias EntityId column as ApplicationId. But it is not working.
Any idea what my options are at this point?
Thanks in advance.
I Just want to create these classes and then use the migration to update my database . My question is :
How to make PostTagMap class ? and here is the photo of the classes relation ..
Classes Picture
public class Post
{
public virtual int Id
{ get; set; }
public virtual string Title
{ get; set; }
public virtual string ShortDescription
{ get; set; }
public virtual string Description
{ get; set; }
public virtual string Meta
{ get; set; }
public virtual string UrlSlug
{ get; set; }
public virtual bool Published
{ get; set; }
public virtual DateTime PostedOn
{ get; set; }
public virtual DateTime? Modified
{ get; set; }
public virtual Category Category
{ get; set; }
public virtual IList<Tag> Tags
{ get; set; }
}
and here is the tag class :
public class Tag
{
public virtual int Id
{ get; set; }
public virtual string Name
{ get; set; }
public virtual string UrlSlug
{ get; set; }
public virtual string Description
{ get; set; }
public virtual IList<Post> Posts
{ get; set; }
}
You really don't need to create a PostTagMap class, the many many relationship is already handled by your navigation Properties in your case public virtual IList<Tag> Tags { get; set; } for Post class and public virtual IList<Post> Posts { get; set; } for Tag Class. This will be handled once you run update-database
i have a little issue.
I am trying to make a Address class were i save all my application's addresses.
The thing is that i want to be able to link several addresses to both customer and company.
Can someone please show me how i should design it?
I use MVC 4 with entityFramework code first.
public class Address
{
[Key]
public int AddressId { get; set; }
public string Street { get; set; }
public string Number { get; set; }
public string ZipCode { get; set; }
public int CountyId { get; set; }
public virtual County County { get; set; }
public int StateId { get; set; }
public virtual State State { get; set; }
public int CountryId { get; set; }
public virtual Country Country { get; set; }
}
public class Customer
{
[Key]
public int CustomerId { get; set; }
public int CompanyId { get; set; }
[Display(Name = "Kund")]
public string Name { get; set; }
public virtual Company Company { get; set; }
// wan't to display a ICollection of addresses.
//public virtual ICollection<Address> Addresses { get; set; }
}
public class Company
{
[Key]
public int CompanyId { get; set; }
[Display(Name = "Organisationsnummer")]
public string OrganisationNumber { get; set; }
[Display(Name = "Företag")]
public string Name { get; set; }
[Display(Name = "Företag skapat")]
public DateTime CreationDate { get; set; }
public virtual ICollection<Customer> Customers { get; set; }
public virtual ICollection<Employee> Employees { get; set; }
// wan't to display a ICollection of addresses.
//public virtual ICollection<Address> Addresses { get; set; }
}
At the following properties and annotations to your classes, it should help Entity Framework understand your relationships:
public class Address
{
[Key]
public int AddressId { get; set; }
public string Street { get; set; }
public string Number { get; set; }
public string ZipCode { get; set; }
public int CustomerId {get;set;}
[ForeignKey("CustomerId")]
public virtual Customer Customer {get;set;}
public int CompanyId {get;set;}
[ForeignKey("CompanyId")]
public virtual Company Company {get;set;}
public int CountyId { get; set; }
[ForeignKey("CountyId")]
public virtual County County { get; set; }
public int StateId { get; set; }
[ForeignKey("StateId")]
public virtual State State { get; set; }
public int CountryId { get; set; }
[ForeignKey("CountryId")]
public virtual Country Country { get; set; }
}
public class Customer
{
[Key]
public int CustomerId { get; set; }
public int CompanyId { get; set; }
[Display(Name = "Kund")]
public string Name { get; set; }
[ForeignKey("CompanyId")]
public virtual Company Company { get; set; }
[InverseProperty("Customer")]
public virtual ICollection<Address> Addresses { get; set; }
}
public class Company
{
[Key]
public int CompanyId { get; set; }
[Display(Name = "Organisationsnummer")]
public string OrganisationNumber { get; set; }
[Display(Name = "Företag")]
public string Name { get; set; }
[Display(Name = "Företag skapat")]
public DateTime CreationDate { get; set; }
[InverseProperty("Company")]
public virtual ICollection<Customer> Customers { get; set; }
[InverseProperty("Company")]
public virtual ICollection<Address> Addresses { get; set; }
[InverseProperty("Company")]
public virtual ICollection<Employee> Employees { get; set; }
}
public class Employee
{
[Key]
public int EmployeeId {get;set;}
public int CompanyId {get;set;}
[ForeignKey("CompanyId")]
public virtual Company Company {get;set;}
}
EDIT: You now have issue of another type. Your DELETE/UPDATE rules are causing the error you're seeing right now. You've most likely set CASCADE delete on multiple paths that lead to same primary key table. For start set all your relationships that look like this:
Then assume this scenario:
You have entities A, B and C.
Entity B has FK to entity A.
Entity C has FK to entity A and entity B.
You're allowed to set cascade delete/update only on one dependency path. This means that you can only do:
Cascade delete between A and B and cascade delete between B and C.
If you however add cascade delete between A and C as well along with above, you'll get an error you have now.
I have 3 tables that needs to be combined in one table. On below you can see the codes.
The problem is each player could play on one or more team on each tournament. Players and teams arranger by every new tournament.
So how can i map it with fluent api or maybe there is a better way to solve it. Thanks from now on.
public class Player
{
public int PlayerID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Phone { get; set; }
public DateTime TimeStamp { get; set; }
public ICollection<Team> Teams { get; set; }
public ICollection<Tournament> Tournaments { get; set; }
}
public class Team
{
public int TeamID { get; set; }
public string Name { get; set; }
public DateTime TimeStamp { get; set; }
public ICollection<Player> Players { get; set; }
public ICollection<Tournament> Tournaments { get; set; }
}
public class Tournament
{
public int TournamentID { get; set; }
public DateTime Date { get; set; }
public int PlaceID { get; set; }
public DateTime TimeStamp { get; set; }
public virtual Place Place { get; set; }
public ICollection<Player> Players { get; set; }
public ICollection<Team> Teams { get; set; }
}
public class BPContext : DbContext
{
public DbSet<Tournament> Tournaments { get; set; }
public DbSet<Place> Places { get; set; }
public DbSet<Table> Tables { get; set; }
public DbSet<Player> Players { get; set; }
public DbSet<Team> Teams { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
I don't see what are you trying to accomplish with this. You have tables that contain all players, all teams and all tournaments.
I suppose there will be a match to be played? What you can do is create another table Matches, to use entity similar to this:
public class Match
{
[Key]
public int MatchId {get;set;}
[ForeignKey("Tournament")]
public int TournamentId {get;set;}
[InverseProperty("Matches")]
public virtual List<Team> Teams {get;set;}
[InverseProperty("Matches")]
public virtual List<Player> Players {get;set;}
[InverseProperty("Matches")]
public virtual Tournament Tournament {get;set;}
}
This new entity holds all 3 previous entities. However you have to modify previous ones to include these changes:
public class Player
{
public int PlayerID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Phone { get; set; }
public DateTime TimeStamp { get; set; }
[InverseProperty("Players")]
public virtual List<Match> Matches { get; set; }
[InverseProperty("Players")]
public virtual List<Team> Teams {get;set;}
}
Getting all tournaments for player can be done with LINQ : ctx.Players.Where(x => x.PlayerId == 15).Matches.Select(x => x.TournamentId).
If you want to see all the players in a tournament: ctx.Matches.Where(x => x.TournamentId ==15).Players.Select(x => x.Name).
public class Team
{
public int TeamID { get; set; }
public string Name { get; set; }
public DateTime TimeStamp { get; set; }
[InverseProperty("Teams")]
public List<Match> Matches {get;set;}
[InverseProperty("Teams")]
public List<Player> Players {get;set;}
}
public class Tournament
{
public int TournamentID { get; set; }
public DateTime Date { get; set; }
public int PlaceID { get; set; }
public DateTime TimeStamp { get; set; }
public virtual Place Place { get; set; }
[InverseProperty("Tournament")]
public virtual List<Match> Matches {get;set;}
}
Today I've been working with MVC for the first time. Also normally I use the EF with model first, but I wanted to try POCO.
So I've made my 3 entities and when I try to make a controller I get an error:
Unable to retrieve metadata for "BookExchange.Models.Exchange". Unable to determine the principal end of an association between the types "BookExchange.Models.Exchange" and "BookExchange.Models.Book". The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.
My 3 classes:
public class Book
{
public int BookID { get; set; }
public string Name { get; set; }
public string Author { get; set; }
public string ISBN10 { get; set; }
public int PersonID { get; set; }
public virtual Person Person { get; set; }
public virtual Exchange Exchange { get; set; }
}
public class Person
{
public int PersonID { get; set; }
public string Name { get; set; }
public virtual ICollection<Book> Books { get; set; }
public virtual ICollection<Exchange> Exchanges { get; set; }
}
public class Exchange
{
[Key]
public int BookID { get; set; }
public int PersonID { get; set; }
public DateTime ReturnDate { get; set; }
public virtual Person Person { get; set; }
public virtual Book Book { get; set; }
}
Does anyone know what I'm doing wrong? I don't want to lose the association properties.
Thanks in advance!
Try adding foreign key properties for your references. E.g.
public class Book
{
public int BookID { get; set; }
public string Name { get; set; }
public string Author { get; set; }
public string ISBN10 { get; set; }
public virtual Person Person { get; set; }
public int PersonID { get; set; }
public virtual Exchange Exchange { get; set; }
public int ExchangeID { get; set; }
}
public class Person
{
public int PersonID { get; set; }
public string Name { get; set; }
public virtual ICollection<Book> Books { get; set; }
public virtual ICollection<Exchange> Exchanges { get; set; }
}
public class Exchange
{
public int ExchangeID { get; set; }
public int BookID { get; set; }
public virtual Book Book { get; set; }
public int PersonID { get; set; }
public virtual Person Person { get; set; }
public DateTime ReturnDate { get; set; }
}
Also, take a look at ScottGu's post on code first and this EF post on conventions.
Try this: (Remove database, so EF will create new)
public class Book
{
public int Id { get; set; }
public string Name { get; set; }
public string Author { get; set; }
public string ISBN { get; set; }
public virtual Person Person { get; set; }
public virtual Exchange Exchange { get; set; }
}
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Book> Books { get; set; }
public virtual ICollection<Exchange> Exchanges { get; set; }
}
public class Exchange
{
public int Id { get; set; }
public DateTime ReturnDate { get; set; }
public virtual Person Person { get; set; }
public virtual Book Book { get; set; }
}
It's your one on one associations.
Remove one reference between exchange or book, so Code-first can decide which one is more important in your one on one relation (Book <--> Exchange)
If you want to know why, you should read this: