EF 4.1 - Model Relationships - asp.net-mvc-3

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; }
}

Related

Entity Framework not binding entity

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.

how to filter nested list using Linq lambda

I have a class person which has a list of addresses and phones as the follow code.
In my query I want a list of person but not including the address and phone that are already deleted, but is always returning all addresses and phones even they flag as deleted. How could I filter those nested lists using lambda?
public class Person{
public int PersonId { get; set; }
public string Name { get; set; }
public virtual ICollection<Address> Addresses { get; set; }
public virtual ICollection<Phone> Phones{ get; set; }
public virtual Company Company { get; set; }
}
public class Address{
public int AddressId { get; set; }
public string Street { get; set; }
public bool Deleted { get; set; }
[ScriptIgnore]
public virtual Person Person { get; set; }
}
public class Phone{
public int PhoneId { get; set; }
public string Number{ get; set; }
public bool Deleted { get; set; }
[ScriptIgnore]
public virtual Person Person { get; set; }
}
return GetDbSet<Person>()
.Include("Address")
.Include("Phones")
.Where(i => i.Company.CompanyId == company.CompanyId)
.OrderByDescending(o => o.CreateTime).ToList();
Just add conditions in your Where clause to exclude deleted address and phone like:
Where(i => i.Company.CompanyId == company.CompanyId &&
i.Address.Any(r=> !r.Deleted) &&
i.Phone.Any(r=> !r.Deleted))

TryUpdateModel Error

First time I can add Allergies into my DB without a problem is As below screen.
But when I try to add 2nd record (after save the first record) then it gives below mentioned run time exception (is as below screen).
Run time Exception
An error occurred while saving entities that do not expose foreign key
properties for their relationships. The EntityEntries property will
return null because a single entity cannot be identified as the source
of the exception. Handling of exceptions while saving can be made
easier by exposing foreign key properties in your entity types. See
the InnerException for details.
Stack Trace (this is for when I try to add 2nd record for medical table.But it is same for Allergies Table also)
Violation of PRIMARY KEY constraint 'PK__Medicati__3214EC0768A0EA12'.
Cannot insert duplicate key in object 'dbo.Medications'. The statement
has been terminated.
Action Method
[HttpPost]
public ActionResult EditMedicalInfo(string providerKey, string ownerKey, string petKey)
{
var pet = Repository.GetPet(ownerKey, petKey);
if (TryUpdateModel(pet))
{
Repository.Save();
}
var url = Url.AbsoluteRouteUrl("PetDetail", new { controller = "customers", action = "detail", providerKey = providerKey, ownerKey = ownerKey, petKey = petKey }) + "#medical";
return Redirect(url);
}
Pet Model
public class Pet {
public Pet() { Id = Guid.NewGuid(); Created = DateTime.Now; }
public Guid Id { get; set; }
public virtual Owner Owner { get; set; }
[StringLength(50), Required]
public string Name { get; set; }
public string Key { get; set; }
public DateTime Created { get; set; }
[Display(Name = "Birth Date"), DataType(DataType.Date)]
public DateTime? BirthDate { get; set; }
[EnumDataType(typeof(PetType)), UIHint("EnumerationList")]
[Required]
public int Type { get; set; }
[Required]
public Guid BreedId { get; set; }
[Display(Name = "Breed"), ForeignKey("BreedId")]
public virtual Breed Breed { get; set; }
[EnumDataType(typeof(Gender)), UIHint("EnumerationList")]
[Required]
public int? Gender { get; set; }
public double Weight { get; set; }
[Display(Name = "License #")]
public string LicenseNumber { get; set; }
[Display(Name = "Microchip #")]
public string MicrochipNumber { get; set; }
public int? AgeValue { get { return (BirthDate.HasValue) ? (int)(DateTime.Today - BirthDate.Value).TotalDays : default(int?); } }
public string Age { get { return (BirthDate.HasValue) ? BirthDate.Value.ToAge() : "Unknown"; } }
public virtual ICollection<PetPhoto> Photos { get; set; }
public virtual ICollection<Appointment> Appointments { get; set; }
public virtual ICollection<MedicalRecordOrder> Orders { get; set; }
public virtual ICollection<PetDocument> Documents { get; set; }
public virtual ICollection<PetNote> Notes { get; set; }
public virtual ICollection<PetProvider> Providers { get; set; }
public virtual ICollection<PetService> PetServices { get; set; }
public Guid? Avatar { get; set; }
public virtual MedicalRecord Medical { get; set; }
public virtual BehavioralRecord Behavioral { get; set; }
public virtual DietRecord Diet { get; set; }
public Guid? EmergencyVeterinarianId { get; set; }
[ForeignKey("EmergencyVeterinarianId")]
public virtual Provider EmergencyVeterinarian { get; set; }
public virtual ICollection<PetContact> Contacts { get; set; }
[EnumDataType(typeof(ProfileCreatorType))]
public int ProfileCreator { get; set; }
[EnumDataType(typeof(PetClassification)), UIHint("EnumerationList")]
public int Classification { get; set; }
[UIHint("InsuranceCarrier")]
public virtual string InsuranceCarrier { get; set; }
// Non persisted extensions
/// <summary>
/// Non Persisted
/// </summary>
[NotMapped]
public List<AppointmentInfo> AppointmentInfos { get; set; }
/// <summary>
/// Non Persisted
/// </summary>
[NotMapped]
public List<AppointmentInfo> SiblingAppointmentInfos { get; set; }
public IList<ReservationRequest> ReservationRequests { get; set; }
[UIHint("QuickList")]
public virtual ICollection<SpecialInstruction> SpecialInstructions { get; set; }
public virtual PetSitterRestrictionPermission PetSitterRestrictionPermission { get; set; }
public virtual PetSitterBehavior PetSitterBehavior { get; set; }
public virtual PetSitterCleaningRecord PetSitterCleaningRecord { get; set; }
public virtual PetSitterNote PetSitterNote { get; set; }
}
Allergy Model
public class Allergy {
public Allergy() { Id = Guid.NewGuid(); }
[ScaffoldColumn(false)]
public Guid Id { get; set; }
public string Name { get; set; }
public string Treatment { get; set; }
}
How could I avoid above error when I try to add 2nd record ?

How to use the mvc 3 dropdownlist

Hello I'm new to mvc 3 and I need some pointers/help populating a dropdownlist. I have 3 classes which are my domain classes. Basically what I want to do is make a dropdownlist that will be populated with a specific members rented movies. What is the easiest way to do this? Is it to use the ViewBag or to make a ViewModel?
public class Member
{
public virtual int MemberId { get; set; }
public virtual long PersonalNr { get; set; }
public virtual string Name { get; set; }
public virtual string LastName { get; set; }
public virtual List<Rental> Rentals { get; set; }
}
public class Movie
{
public virtual int MovieId { get; set; }
public virtual string Name { get; set; }
public virtual bool IsInStock { get; set; }
}
public class Rental
{
public virtual int RentalId { get; set; }
public virtual int MovieId { get; set; }
public virtual Movie Movie { get; set; }
public virtual int MemberId { get; set; }
public virtual Member Member { get; set; }
public DateTime startDate { get; set; }
public DateTime dueDate { get; set; }
}
The easiest way is
#Html.DropDownListFor(
x => x.SelectedRentalId,
Model.Rentals
)
to know a little better on how to use it, including the select part, se Darin's answer
https://stackoverflow.com/a/6807331/28004

Entity Framework also Linq advice needed

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

Resources