i have got on my DB 3 tables
movies, workers, workermovies ( this is the Relationship table )
public class Movie
{
public Movie()
{
Genres = new List<Genre>();
Formats = new List<Format>();
ProductionCompanies = new List<ProductionCompany>();
Workers = new List<Worker>();
}
public int Id { get; set; }
public string Title { get; set; }
public DateTime ReleaseDate { get; set; }
public string StoryLine { get; set; }
public int RunTime { get; set; }
[ForeignKey("MPAARateId")]
public MPAARate MPAARate { get; set; }
public int MPAARateId { get; set; }
public byte[] ImageData { get; set; }
public string ImageMimeType { get; set; }
public DateTime CreatedDate { get; set; }
public string OfficialSite { get; set; }
public int Budget { get; set; }
public int StatusId { get; set; }
public virtual ICollection<Genre> Genres { get; set; }
public virtual ICollection<Format> Formats { get; set; }
public virtual ICollection<ProductionCompany> ProductionCompanies { get; set; }
public virtual ICollection<Worker> Workers { get; set; }
}
public class Worker
{
public int Id { get; set; }
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public DateTime Birthday { get; set; }
public string Biography { get; set; }
public string BornName { get; set; }
public double Height { get; set; }
public DateTime? Died { get; set; }
public byte[] ImageData { get; set; }
public string ImageMimeType { get; set; }
public bool IsActor { get; set; }
public bool IsDirector { get; set; }
public bool IsWriter { get; set; }
public bool IsProducer { get; set; }
public bool IsStar { get; set; }
public virtual ICollection<Movie> Movies { get; set; }
}
in this Relation i got the movieId and the workerId
but i also got some more fields if the person acted or writen or producer etc.
how do i define the relation entity class if needed
and when i want to get just the ppl that acted in the movie how do i wrote such a linq
query
You need to introduce an additional entity in your model WorkerMovie and convert the many-to-many relationship between Worker and Movie into two one-to-many relationships - one between Worker and WorkerMovie and the other between Movie and WorkerMovie. A sketch:
public class WorkerMovie
{
[Key, Column(Order = 0)]
public int WorkerId { get; set; }
[Key, Column(Order = 1)]
public int MovieId { get; set; }
public Worker Worker { get; set; }
public Movie Movie { get; set; }
public bool WorkedAsActor { get; set; }
public bool WorkedAsWriter { get; set; }
public bool WorkedAsProducer { get; set; }
// etc.
}
public class Movie
{
// ...
public virtual ICollection<WorkerMovie> WorkerMovies { get; set; }
// remove ICollection<Worker> Workers
}
public class Worker
{
// ...
public virtual ICollection<WorkerMovie> WorkerMovies { get; set; }
// remove ICollection<Movie> Movies
}
If you want only to find the workers who were actors in a particular movie with a movieId you can write:
var workersAsActors = context.WorkerMovies
.Where(wm => wm.MovieId == movieId && wm.WorkedAsActor)
.Select(wm => wm.Worker)
.ToList();
Here is another answer to a very similar question with many more examples of possible queries: Create code first, many to many, with additional fields in association table
Related
I am use code first model with a relationship below
public class ApplicationUser : IdentityUser
{
public string UserFirstName { get; set; }
public string UserLastName { get; set; }
public string UserSchool { get; set; }
public UserProfileData UserProfileData { get; set; }
public int? MedicalSpecialtyId { get; set; }
public virtual MedicalSpecialty MedicalSpecialty { get; set; }
// public int? AnalyticsDataId { get; set; }
// public ICollection<AnalyticsData> AnalyticsDatas { get; set; }
}
public class MedicalSpecialty
{
public int Id { get; set; }
public string Description { get; set; }
// public int ApplicationUserId { get; set; }
public virtual ApplicationUser ApplicationUser { get; set; }
public ICollection<ProgramDetailData> ProgramDetailDatas { get; set; }
}
And when I try to get a User's associated MedicalSpecialty object it is NULL
userSpecialtyName = currentUser.MedicalSpecialty.Description;
BUT when I run this code above it the currentUser.MedicalSpecialty is no longer NULL. What happened?? Somehow that LINQ query woke up the object and filled it with data
var userSpecialtyId = currentUser.MedicalSpecialtyId;
userSpecialtyName = _medicalSpecialtyRepository.Find
(x => x.Id == userSpecialtyId).FirstOrDefault().Description;
userSpecialtyName = currentUser.MedicalSpecialty.Description;
I have the following db structure:
I am using EF6 to create the entities from database and have the following classes created by EF6:
public partial class Mechanic
{
public Mechanic()
{
this.MechanicAddresses = new HashSet<MechanicAddress>();
this.MechanicServices = new HashSet<MechanicService>();
}
public string ID { get; set; }
public string Email { get; set; }
public bool EmailConfirmed { get; set; }
public string PasswordHash { get; set; }
public string SecurityStamp { get; set; }
public string PhoneNumber { get; set; }
public bool PhoneNumberConfirmed { get; set; }
public bool TwoFactorEnabled { get; set; }
public Nullable<System.DateTime> LockoutEndDateUtc { get; set; }
public bool LockoutEnabled { get; set; }
public int AccessFailedCount { get; set; }
public string UserName { get; set; }
public string CompanyName { get; set; }
public string ContactName { get; set; }
public string MobileNumber { get; set; }
public Nullable<bool> IsMobile { get; set; }
public string Url { get; set; }
public string FaceBookUrl { get; set; }
public string TwitterUrl { get; set; }
public string Description { get; set; }
public string Discriminator { get; set; }
public bool IsEnabled { get; set; }
public bool IsAuthorised { get; set; }
public string Logo { get; set; }
public System.DateTime CreationTimestamp { get; set; }
public virtual ICollection<MechanicAddress> MechanicAddresses { get; set; }
public virtual ICollection<MechanicService> MechanicServices { get; set; }
}
public partial class MechanicAddress
{
public int ID { get; set; }
public string MechanicId { get; set; }
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string AddressLine3 { get; set; }
public string District { get; set; }
public string Region { get; set; }
public string PostalCode { get; set; }
public int CountryId { get; set; }
public System.DateTime CreationTimestamp { get; set; }
public bool IsPrimary { get; set; }
public Nullable<double> Latitude { get; set; }
public Nullable<double> Longitude { get; set; }
public System.Data.Entity.Spatial.DbGeography Location { get; set; }
public virtual Country Country { get; set; }
public virtual Mechanic Mechanic { get; set; }
}
public partial class MechanicService
{
public int ID { get; set; }
public string MechanicId { get; set; }
public string Service { get; set; }
public virtual Mechanic Mechanic { get; set; }
}
The data is correct so i expect to get data in all entities.
When i run the following linq query in my DAL:
Mechanic mech = context.Mechanics.Where(a => a.ID == id).Include(a => a.MechanicAddresses).Include(a => a.MechanicServices).FirstOrDefault();
It returns the mechanic and mechanicAddresses but mechanicServices is always empty (count == 0).
When i run the same query in LinqPad I get all entities filled as expected.
I have removed the edmx and re-created it but still get the same issue.
Please check if "MultipleActiveResultSets" is set to true and LazyLoadingEnabled is enabled in connection string. It may help.
And what about your OnModelCreating?
protected override void OnModelCreating(DbModelBuilder modelBuilder)
It's not necessary to use Include if you have LazyLoading (virtual). And If it works fine in LinqPad try to do migration into empty DB (just test). And then try to get data from test DB.
The only way i was able to resolve this was to:
delete the EDMX
script the create for the mechanicsServices table
script the data
drop the mechanicsServices table
run the create table script from above
run the insert data script
regenerate the EDMX
This now works, WTF! Can't explain it.
I know it's always best to understand what went wrong but this one beat me.
I had same problem.
If you using git, please check .edmx file old version. SSDL content may be missing.
I'm trying to use Enum support with EF 5 and dot.NET 4.5.
The situation I have is the following.
POCO:
public partial class tbl_pp_Message
{
public tbl_pp_Message()
{
this.tbl_pp_MessageDistribution = new List<tbl_pp_MessageDistribution>();
}
public int MessageId { get; set; }
public string Subject { get; set; }
public string From { get; set; }
public string Body { get; set; }
public int PriorityId { get; set; }
public System.DateTime CreateDate { get; set; }
public int CreateById { get; set; }
[ForeignKey("PriorityId")]
public virtual tbl_pp_MessagePriority tbl_pp_MessagePriority { get; set; }
public virtual ICollection<tbl_pp_MessageDistribution> tbl_pp_MessageDistribution { get; set; }
}
public partial class tbl_pp_MessagePriority
{
public tbl_pp_MessagePriority()
{
this.tbl_pp_Message = new List<tbl_pp_Message>();
}
public int MessagePriorityId { get; set; }
public string Description { get; set; }
public Nullable<int> DisplayOrder { get; set; }
public bool ShowAlert { get; set; }
public virtual ICollection<tbl_pp_Message> tbl_pp_Message { get; set; }
}
With the code listed above NOT using an ENUM the world is happy.
When I try to add an Enum the POCO will look like this.
[Flags]
public enum MessagePriorityEnum : int
{
NONE = 0,
Urgent = 1,
Normal = 2,
Low = 3
}
public partial class tbl_pp_Message
{
public tbl_pp_Message()
{
this.tbl_pp_MessageDistribution = new List<tbl_pp_MessageDistribution>();
}
public int MessageId { get; set; }
public string Subject { get; set; }
public string From { get; set; }
public string Body { get; set; }
public MessagePriorityEnum PriorityId { get; set; }
public System.DateTime CreateDate { get; set; }
public int CreateById { get; set; }
[ForeignKey("PriorityId")]
public virtual tbl_pp_MessagePriority tbl_pp_MessagePriority { get; set; }
public virtual ICollection<tbl_pp_MessageDistribution> tbl_pp_MessageDistribution { get; set; }
}
This will not work during a save because it doesn't like the ForeignKey attribute. This error will be thrown during a save.
Schema specified is not valid. Errors:
(129,6) : error 0112: The types of all properties in the Dependent Role of a referential constraint must be the same as the corresponding property types in the Principal Role. The type of property 'PriorityId' on entity 'tbl_pp_Message' does not match the type of property 'MessagePriorityId' on entity 'tbl_pp_MessagePriority' in the referential constraint 'tbl_pp_MessagePriority_tbl_pp_Message'.
If the navigation for tbl_pp_MessagePriority is removed from tbl_pp_Message POCO. And the navigation removed from tbl_pp_MessagePriority POCO back to tbl_pp_Message then it works.
With out the navigation removed it will generate a SQL statement like this.
insert [dbo].[tbl_pp_Message]
([Subject],
[From],
[Body],
[PriorityId],
[CreateDate],
[CreateById],
[tbl_pp_MessagePriority_MessagePriorityId])
values ('Test ENUM EF Code First 5.0' /* #0 */,
'Daniel.Bivens' /* #1 */,
'Test 01 Enum Body - The Magic Unicorn Edition' /* #2 */,
2 /* #3 */,
'2013-05-23T10:52:09' /* #4 */,
5 /* #5 */,
null)
select [MessageId]
from [dbo].[tbl_pp_Message]
where ##ROWCOUNT > 0
and [MessageId] = scope_identity()
It would be ok if the tbl_pp_MessagePriority_MessagePriorityId was not added to the insert.
What can be done to keep the navigaion in EF code first while using ENUM support? Is there a DataAnnotation or a Mapping API?
Please post any suggestions you may have. This project is not using an EDMX/T4 template.
Working POCO:
public partial class tbl_pp_Message
{
//public tbl_pp_Message()
//{
// this.tbl_pp_MessageDistribution = new List<tbl_pp_MessageDistribution>();
//}
public int MessageId { get; set; }
public string Subject { get; set; }
public string From { get; set; }
public string Body { get; set; }
public MessagePriorityEnum PriorityId { get; set; }
public System.DateTime CreateDate { get; set; }
public int CreateById { get; set; }
//[ForeignKey("PriorityId")]
//public virtual tbl_pp_MessagePriority tbl_pp_MessagePriority { get; set; }
//public virtual ICollection<tbl_pp_MessageDistribution> tbl_pp_MessageDistribution { get; set; }
}
public partial class tbl_pp_MessagePriority
{
//public tbl_pp_MessagePriority()
//{
// this.tbl_pp_Message = new List<tbl_pp_Message>();
//}
public int MessagePriorityId { get; set; }
public string Description { get; set; }
public Nullable<int> DisplayOrder { get; set; }
public bool ShowAlert { get; set; }
//public virtual ICollection<tbl_pp_Message> tbl_pp_Message { get; set; }
}
The working POCO would be ok if no navigation was needed.
The thing I was missing was setting the look-up table primary key to the same ENUM type instead of an int.
Working POCO with ENUM and navigation.
public partial class tbl_pp_Message
{
public tbl_pp_Message()
{
this.tbl_pp_MessageAction = new List<tbl_pp_MessageAction>();
this.tbl_pp_MessageAttachment = new List<tbl_pp_MessageAttachment>();
this.tbl_pp_MessageDistribution = new List<tbl_pp_MessageDistribution>();
}
public int MessageId { get; set; }
public string Subject { get; set; }
public string From { get; set; }
public string Body { get; set; }
public MessageTypeEnum TypeId { get; set; }
public System.DateTime CreateDate { get; set; }
public int CreateById { get; set; }
[ForeignKey("TypeId")]
public virtual tbl_pp_MessageType tbl_pp_MessageType { get; set; }
public virtual ICollection<tbl_pp_MessageAction> tbl_pp_MessageAction { get; set; }
public virtual ICollection<tbl_pp_MessageAttachment> tbl_pp_MessageAttachment { get; set; }
public virtual ICollection<tbl_pp_MessageDistribution> tbl_pp_MessageDistribution { get; set; }
}
public partial class tbl_pp_MessageType
{
public tbl_pp_MessageType()
{
this.tbl_pp_Message = new List<tbl_pp_Message>();
}
[Key]
public MessageTypeEnum MessageTypeId { get; set; }
public string Description { get; set; }
public Nullable<int> DisplayOrder { get; set; }
public bool ShowAlert { get; set; }
public virtual ICollection<tbl_pp_Message> tbl_pp_Message { get; set; }
}
I'm building website in MVC 3.
i am using EF code first in existing database.
my ET inside the model look like that:
public class Pages
{
[Required]
public int ID { get; set; }
public int ParentID { get; set; }
[Required]
public int PageType { get; set; }
[Required]
[DataType(DataType.Text)]
[DisplayName("כותרת")]
public string Title { get; set; }
public string SearchWords { get; set; }
public string Leng { get; set; }
public int? Sort { get; set; }
public string Modules { get; set; }
[ForeignKey("PageType")]
public virtual PagesType Type { get; set; }
public virtual IEnumerable<PagesType> Types { get; set; }
[ForeignKey("PageID")]
public ICollection<PageContent> PageContent { get; set; }
[ForeignKey("PageID")]
public virtual ICollection<ImagesTable> Images { get; set; }
}
public class PageContent
{
public int ID { get; set; }
public int PageID { get; set; }
public string Header { get; set; }
public string Text { get; set; }
[ForeignKey("ID")]
public virtual ICollection<Pages> Pages { get; set; }
}
as you see in my fist table that cold Pages i have a relationship to another table that named PageContent.
in my Pages class i had this code
[ForeignKey("PageID")]
public ICollection<PageContent> PageContent { get; set; }
now, when i trying to add new pageContent into new page i get an error.
see this code
public ActionResult AddPage(PageModel page)
{
SystemLogic cmd = new SystemLogic();
page.Leng = "he";
Models.Pages p = new Pages();
p.ParentID = page.ParentID;
PageContent pageContent = new PageContent();
pageContent.Text = page.Content;
p.PageContent.Add(pageContent);
The error is
Object reference not set to an instance of an object.
What i did wrong?
You will get the NRE at p.PageContent.Add(pageContent); because the collection is not initialized. Initialize the collections inside the constructor of Pages class.
public class Pages
{
public Pages()
{
PageContent = List<PageContent>();
Images = List<ImagesTable>();
}
[Required]
public int ID { get; set; }
public int ParentID { get; set; }
[Required]
public int PageType { get; set; }
[Required]
[DataType(DataType.Text)]
[DisplayName("כותרת")]
public string Title { get; set; }
public string SearchWords { get; set; }
public string Leng { get; set; }
public int? Sort { get; set; }
public string Modules { get; set; }
[ForeignKey("PageType")]
public virtual PagesType Type { get; set; }
public virtual IEnumerable<PagesType> Types { get; set; }
[ForeignKey("PageID")]
public ICollection<PageContent> PageContent { get; set; }
[ForeignKey("PageID")]
public virtual ICollection<ImagesTable> Images { get; set; }
}
Or before you add objects to the collection
if (p.PageContent == null) p.PageContent = new List<PageContent>();
p.PageContent.Add(pageContent);
You should consider using proper naming conventions(eg Page instead of Pages).
I'm trying to create a quick ASP.NET MVC 3 application using the RC version of EF 4.1. I have two models:
public class Race
{
public int RaceId { get; set; }
public string RaceName { get; set; }
public string RaceDescription { get; set; }
public DateTime? RaceDate { get; set; }
public decimal? Budget { get; set; }
public Guid? UserId { get; set; }
public int? AddressId { get; set; }
public virtual Address Address { get; set; }
}
and
public class Address
{
public int AddressId { get; set; }
public string Street { get; set; }
public string StreetCont { get; set; }
public string City { get; set; }
public string State { get; set; }
public string ZipCode { get; set; }
public virtual Race Race { get; set; }
}
I get the following error when trying to insert a new Race:
Unable to determine the principal end
of an association between the types
'rcommander.Models.Race' and
'rcommander.Models.Address'. The
principal end of this association must
be explicitly configured using either
the relationship fluent API or data
annotations.
Shouldn't it recognize RaceId as the primary key of the Races table and AddressId as the FK to the Addresses table automatically? Am I missing something?
Thanks!
The problem here seems to be that EntityFramework can't recognize where the foreing key is, as you are holding cross references in both objects. Not being sure what you want to achieve, I may suggest something like this:
public class Race
{
public int RaceId { get; set; }
public string RaceName { get; set; }
public string RaceDescription { get; set; }
public DateTime? RaceDate { get; set; }
public decimal? Budget { get; set; }
public Guid? UserId { get; set; }
public int? AddressId { get; set; }
public virtual Address Address { get; set; }
}
public class Address
{
public int AddressId { get; set; }
public string Street { get; set; }
public string StreetCont { get; set; }
public string City { get; set; }
public string State { get; set; }
public string ZipCode { get; set; }
}
Skipping reference to Race in second entity.
The problem here is 1:1 relation between Address and Race! You probably want to map it as 1:N so you need to modify address to:
public class Address
{
public int AddressId { get; set; }
public string Street { get; set; }
public string StreetCont { get; set; }
public string City { get; set; }
public string State { get; set; }
public string ZipCode { get; set; }
public virtual ICollection<Race> Races { ... }
}
If you want to use 1:1 then you can't use AddressId in Race but AddressId in Address must be foreign key of Race because entity framework can achive 1:1 only be "sharing" primary key.
For one-to-one relationship, you need to add "[required]" attribute in the second class. See below:
public class Race
{
public int RaceId { get; set; }
public string RaceName { get; set; }
public string RaceDescription { get; set; }
public DateTime? RaceDate { get; set; }
public decimal? Budget { get; set; }
public Guid? UserId { get; set; }
public int? AddressId { get; set; }
public virtual Address Address { get; set; }
}
public class Address
{
public int AddressId { get; set; }
public string Street { get; set; }
public string StreetCont { get; set; }
public string City { get; set; }
public string State { get; set; }
public string ZipCode { get; set; }
[required]
public Race Race { get; set; }
}
There is a good post: Associations in EF Code First CTP5: Part 2 – Shared Primary Key Associations
http://weblogs.asp.net/manavi/archive/2010/12/19/entity-association-mapping-with-code-first-one-to-one-shared-primary-key-associations.aspx
It recognizes Id as the primary key by convention. So what you need to do:
public class Race
{
[Key]
public int RaceId { get; set; }
public string RaceName { get; set; }
public string RaceDescription { get; set; }
public DateTime? RaceDate { get; set; }
public decimal? Budget { get; set; }
public Guid? UserId { get; set; }
public int? AddressId { get; set; }
public virtual Address Address { get; set; }
}
and
public class Address
{
[Key]
public int AddressId { get; set; }
public string Street { get; set; }
public string StreetCont { get; set; }
public string City { get; set; }
public string State { get; set; }
public string ZipCode { get; set; }
[ForeignKey("RaceId")] // Maybe telling it what the ForeignKey is will help?
public virtual Race Race { get; set; }
}
The [Key] attribute indicates that it should be the PrimaryKey
If you don't want this, you need to rename your primary keys to simply public int Id {get; set; }
I think it would be solved also like this... I assumed that an address is not required to be associated with a race, but a race must always be associated with an address.
I had the same problem with Patients and Incidents and i solved it with InverseProperty which is actually the same with foreign key, but the other direction
public class Race
{
public int RaceId { get; set; }
public string RaceName { get; set; }
public string RaceDescription { get; set; }
public DateTime? RaceDate { get; set; }
public decimal? Budget { get; set; }
public Guid? UserId { get; set; }
public int AddressId { get; set; }
[ForeignKey("AddressId")]
public virtual Address Address { get; set; }
}
public class Address
{
public int AddressId { get; set; }
public string Street { get; set; }
public string StreetCont { get; set; }
public string City { get; set; }
public string State { get; set; }
public string ZipCode { get; set; }
public int? RaceId { get; set; }
[InverseProperty("RaceId")]
public Race Race { get; set; }
}