I have an Employee table that links employees to their contact info. I have it set up like so:
[ForeignKey("AddressId")]
public virtual Address Address { get; set; }
[ForeignKey("HomePhoneId")]
public virtual PhoneNumber HomePhone { get; set; }
[ForeignKey("WorkPhoneId")]
public virtual PhoneNumber WorkPhone { get; set; }
[ForeignKey("CellPhoneId")]
public virtual PhoneNumber CellPhone { get; set; }
When I try to load employees from the database, however, it automatically renames the columns, completely overriding the attributes:
Invalid column name 'PhoneNumber_Id'.
Invalid column name 'PhoneNumber_Id1'.
Invalid column name 'PhoneNumber_Id2'.
Invalid column name 'Address_Id'.
Why is it doing this?
As stated by #mcbowes, it is hard to tell without seeing the rest of your Employee class, but most likely you are missing the following in your class:
public int AddressId { get; set; }
public int HomePhoneId { get; set; }
public int WorkPhoneId { get; set; }
public int CellPhoneId { get; set; }
The IDs were all properly specified for each navigation property. It seems the problem had to do with the navigation properties on each PhoneNumber and Address object that linked back to the Employee. I don't need them for now, so removing those navigation properties corrected the issue.
As an expansion on #peinearydevelopment set up your PhoneNumber:
public class PhoneNumber
{
public PhoneNumber(string name, int areaCode, string number)
{
Name = name;
AreaCode = areaCode;
Number = number;
}
public int ID { get; set; }
public string Name { get; set; }
public int AreaCode { get; set; }
public string Number { get; set; }
}
}
Set up your Employee:
public class Person
{
public Person(string first, string last, PhoneNumber home, PhoneNumber cell)
{
First = first;
Last = last;
HomeNumber = home;
CellNumber = cell;
}
public int ID { get; set; }
public string First { get; set; }
public string Last { get; set; }
public int HomePhone_ID { get; set; }
public int CellNumber_ID { get; set; }
public virtual PhoneNumber HomeNumber { get; set; }
public virtual PhoneNumber CellNumber { get; set; }
}
}
And your Context
public class PersonContext : DbContext
{
public DbSet<Person> People { get; set; }
public DbSet<PhoneNumber> PhoneNumbers { get; set; }
}
As you can see, relationships are maintained, but you do need to explicitly tell your application which fields hold the identifiers, not just which tables have the relationships.
Related
Entity framework changed the column name in the DB, and isn't giving me it's value.
Here are my classes:
public class Settings
{
[Key]
public int ID { get; set; }
public string Setting { get; set; }
public string MoreDetail { get; set; }
public SettingTypes Type { get; set; }
public SettingGroups SettingGroup { get; set; }
public int? MinMembership { get; set; }
public string DefaultValue { get; set; }
public int? ParentID { get; set; }
public int Order { get; set; }
}
public class SettingTypes
{
[Key]
public int ID { get; set; }
[MaxLength(35)]
public string TypeName { get; set; }
}
public class SettingGroups
{
[Key]
public int ID { get; set; }
[MaxLength(35)]
public string GroupName { get; set; }
}
In the DB you can see that it changed the name of the two columns:
When I try to loop through the results, type is null:
How do I retrieve this value? I've tried renaming the columns in the class and in the DB but that just breaks more things. What's the proper way to handle this?
Thanks!
Dangit, I figured it out. Spent way to much time doing so.
It was as simple as adding "virtual" to the properties:
public virtual SettingTypes Type { get; set; }
public virtual SettingGroups SettingGroup { get; set; }
Now I can address it like:
setting.Type.TypeName
Hope this saves someone else some time.
I'm basically trying to enforce this in Entity Framework: Require Only One Of Multiple Columns Be Not Null
My database has several 1:m relationships where the child entity belongs to one of several parent entities. For example, let's say I have tables for Teachers, Students, and Guardians. Each of those can have many PhoneNumbers and EmailAddresses. I am using EF Code First, and my models look something like:
public class Teacher {
public int Id { get; set; }
public string Name { get; set; }
public List<PhoneNumber> PhoneNumbers { get; set; }
public List<EmailAddress> EmailAddresses { get; set; }
}
public class Student {
public int Id { get; set; }
public string Name { get; set; }
public List<PhoneNumber> PhoneNumbers { get; set; }
public List<EmailAddress> EmailAddresses { get; set; }
}
public class Guardian {
public int Id { get; set; }
public string Name { get; set; }
public List<PhoneNumber> PhoneNumbers { get; set; }
public List<EmailAddress> EmailAddresses { get; set; }
}
public class PhoneNumber {
public int Id { get; set; }
public string Number { get; set; }
}
public class EmailAddress {
public int Id { get; set; }
public string Email { get; set; }
}
When I run the migration, this creates the database with the tables/columns I would expect. The PhoneNumbers and EmailAddresses tables each have columns Teacher_Id, Student_Id, and Guardian_Id, which are foreign keys to their respective parent entity. However, there are no constraints on how many parent entities can be set on the child. For example, I can create a PhoneNumber that has all three parent IDs set to null, or I can set both a Teacher_Id and a Guardian_Id.
I tried adding a required attribute to the parents like so:
public class Teacher { // Also Student/Guardian
public int Id { get; set; }
public string Name { get; set; }
[Required]
public List<PhoneNumber> PhoneNumbers { get; set; }
[Required]
public List<EmailAddress> EmailAddresses { get; set; }
}
That does not seem to have any effect.
I think there is no way to do this on entities. Instead, create a migration and try to alter the table in migration class like this:
public partial class YourMigrationName: Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql("ALTER TABLE [dbo].[PhoneNumber]
WITH CHECK ADD CONSTRAINT [CK_PhoneNumer_Teacher_Student_Guardian] CHECK (Teacher_Id
is not null or Student_Id is not null or Guardian_Id is not null)
GO
ALTER TABLE [dbo].[EmailAddress] WITH CHECK ADD CONSTRAINT
[CK_EmailAddress_Teacher_Student_Guardian] CHECK (Teacher_Id is not null or
Student_Id is not null or Guardian_Id is not null)
");
}
}
Try this:
public class PhoneNumber
{
public int Id { get; set; }
public string Number { get; set; }
//Added this code:
[Required]
public Teacher Teacher { get; set;}
}
public class EmailAddress {
public int Id { get; set; }
public string Email { get; set; }
//Added this code:
[Required]
public Teacher Teacher { get; set;}
}
That would make sure you cannot create PhoneNumber without Teacher. You can also do this:
public class PhoneNumber
{
public int Id { get; set; }
public string Number { get; set; }
public int TeacherId
public Teacher Teacher { get; set;}
}
That would also detect that you want to add constraint on your PhoneNumber. Both ways work fine.
I have Country, City, Region and "Account Address" tables.
I want to create foreign key columns in "Account Address" pointing to Country, City, Region tables.
I have this code but it throws an error on creating database
The property \u0027Account_Id\u0027 cannot be configured as a
navigation property. The property must be a valid entity type and the
property should have a non-abstract getter and setter. For collection
properties the type must implement
After New Edit
public class Cities
{
[Key]
public int City_Id { get; set; }
public string City_name { get; set; }
public int Country_Id { get; set; }
[ForeignKey("Country_Id")]
public Countries countries { get; set; }
}
public class Region
{
[Key]
public int Region_Id { get; set; }
public string Region_name { get; set; }
public int City_Id { get; set; }
[ForeignKey("City_Id")]
public Countries countries { get; set; }
}
public class Accounts
{
[Key]
public int Account_Id { get; set; }
public string Fullname { get; set; }
public string Email { get; set; }
public string password { get; set; }
public int Cell_phone { get; set; }
public string Role { get; set; }
public int? estate_office_Id { get; set; }
[ForeignKey("estate_office_Id")]
public Estate_office estate_office { get; set; }
public List<Ads> ads { get; set; }
}
public class Account_address
{
[Key]
public int Id { get; set; }
[ForeignKey("Account_Id"), Column(Order = 0)]
public int Account_Id { get; set; }
[ForeignKey("Country_Id"), Column(Order = 1)]
public int Country_Id { get; set; }
[ForeignKey("City_Id"), Column(Order = 2)]
public int City_Id { get; set; }
[ForeignKey("Region_Id"), Column(Order = 3)]
public int Region_Id { get; set; }
public Accounts accounts { get; set; }
public Countries countries { get; set; }
public Cities cities { get; set; }
public Region region { get; set; }
}
You need to define public properties as shown below on the Account_address class.Then only EF will know how to map those navigation properties correctly.
public class Account_address
{
......
......
public Accounts accounts { get; set; } //like this
public Countries countries { get; set; } //like this
public Cities cities { get; set; } //like this
public Region region { get; set; } //like this
}
Update :
Hence you're not using singular naming convention for the classes,you have encountered this issue.Either you have to change the name of classes as singular or need to change the navigational property names a shown below.You have to do this for all the places.Here I have shown only for the Accounts class related navigational property.
[ForeignKey("Accounts_Id"), Column(Order = 0)]
public int Accounts_Id { get; set; }
My Advice is to follow the basic naming conventions.Then you can avoid lot of above kind of weird errors.
Hi every one I want to save complex data using Entity Framework and C#. I have 2 classes Product and Order defined as follows
Product Class
public class Product
{
[Key]
public int Id { get; set; }
public string SKU_Code { get; set; }
public string Product_Name { get; set; }
public string Quantity { get; set; }
public string Price { get; set; }
public string Image { get; set; }
public DateTime Created_Date { get; set; }
public DateTime Modified_Date { get; set; }
}
Order Class
public class Order
{
[Key]
public long ID { get; set; }
public string Order_Id { get; set; }
public string Payment_Type { get; set; }
public string Customer_Name { get; set; }
public string Shipping_Address { get; set; }
public DateTime Order_Date { get; set; }
public DateTime Modified_Date { get; set; }
public bool Flag { get; set; }
public List<Product> ProductDetails { get; set; }
}
And I want to save data Order details and my piece of code is as follows.
public Order Add(Order odrerDetails)
{
using (var context = new EcommerceDBContext())
{
var MyOrder_Id = Helper.Random(7); //Generate random orderID from my class
foreach (var detail in odrerDetails.ProductDetails)
{
odrerDetails.Order_Id = MyOrder_Id;
odrerDetails.Quantity = Convert.ToInt32(detail.Quantity);
odrerDetails.Amount = Convert.ToDouble(detail.Price);
//Other Details
context.objOrderListing.Add(odrerDetails);
}
context.SaveChanges();
return odrerDetails;
}
}
This gives me perfect data but when it comes to context.SaveChanges(); it return's me error.
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.
To me you domain model seems all wrong. The order should just be used for grouping, its a typical e-commerce scenario.
When you get a receipt of your purchases, you get one receipt with every Item and price listed next to it. Its considered as one order of multiple things, not multiple orders of multiple things.
Reading your last comment, you cant have multiple orders with the same order id. Try to understand the domain first before trying to solve it with code. Also,you have no notion of a Customer with an Order.
public class Product
{
[Key]
public int Id { get; set; }
public string SKU_Code { get; set; }
public string Product_Name { get; set; }
public string Price { get; set; }
public string Image { get; set; }
public DateTime Created_Date { get; set; }
public DateTime Modified_Date { get; set; }
}
public class Order
{
[Key]
public long ID { get; set; }
public string Order_Id { get; set; }
public string Payment_Type { get; set; }
public string Customer_Name { get; set; }
public string Shipping_Address { get; set; }
public DateTime Order_Date { get; set; }
public DateTime Modified_Date { get; set; }
public bool Flag { get; set; }
public List<OrderLineItem> Items { get; set; }
}
public class OrderLineItem
{
[Key]
public long ID { get; set; }
public long Order_Id { get; set; }
public long Product_Id {get; set;}
public int Quantity {get; set;}
}
I work with EF for the first time so I don't know is situation like this normal or I have serious performance issues.
I have following situation:
Bellow are the classes that I have. Item is the main object here. So when I pull a list of Items from database I get for example 1000 items. And now each of this item has all properties filed with data. City contains Country, Country contains list of cities, User has list of created items, each item all data again, city, city has country, country list of cities etc etc...
Maybe I am worrying too much and I don't know should this object's contain all those data and does this make performance issues, or I am doing something wrong here?
public abstract class Item
{
[Key]
public int ItemId { get; set; }
public int ItemTypeId { get; set; }
public Guid UserId { get; set; }
public DateTime CreatedOnDate { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public int? MediaId { get; set; }
public int CityId { get; set; }
public virtual City City { get; set; }
public virtual User User { get; set; }
public virtual ICollection<ItemInBoard> ItemsInBoard { get; set; }
public virtual ICollection<Like> Likes { get; set; }
public virtual ICollection<Comment> Comments { get; set; }
}
public class City
{
public int CityId { get; set; }
public string Name { get; set; }
public double Longitude { get; set; }
public double Latitude { get; set; }
public int CountryId { get; set; }
public virtual Country Country { get; set; }
}
public class Country
{
public int CountryId { get; set; }
public string Name { get; set; }
public string CountryCode { get; set; }
public virtual ICollection<City> Cities { get; set; }
}
public class User
{
public Guid UserId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public bool Gender { get; set; }
public DateTime? BirthDay { get; set; }
public string AboutMe { get; set; }
public int? MediaId { get; set; }
public int CityId { get; set; }
public virtual City City { get; set; }
public virtual ICollection<Item> Items { get; set; }
public virtual ICollection<Board> Boards { get; set; }
public virtual ICollection<Like> Likes { get; set; }
}
It is up to you. This is a concept called lazy loading. You can enable or disable lazy loading with this code:
context.Configuration.LazyLoadingEnabled = false;
context.Configuration.LazyLoadingEnabled = true;
When enabling this option none of the dependent entities will be loaded. To enforce dependent entities to load you can use the Include lambada expression like this:
var test = context.Tests.Include("SomeOtherDependentEntity");
Hope I got you and this is what you meant.
I would say that what you have is fine for general business logic.
When I have to do a lot of time sensitive processing in a read-only fashion I use SQL commands like this to get exactly and only exactly what I want.
public class myQueryClass
{
public string Property1 { get; set; }
public string Property2 { get; set; }
}
var context = new MyDbContext();
context.Database.SqlQuery<myQueryClass>("SELECT Property1 = acolumn, Property2 = acolumn2 FROM myTable WHERE something = somestate");