I have two tables
PropertyListing - It stores the details of the property user add, with an FK
PropertyAvailability - It's a table that stores property status ( Now Available, After 3 Months, ...)
I am trying to enforce a one-to-many relation with these two tables (Fluent API) like this
public partial class PropertyListing
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
public string StreetAddress { get; set; }
//the column that links with PropertyAvaibility table PK
public byte? Availability { get; set; }
public bool Status { get; set; }
public virtual PropertyAvailability PropertyAvailability { get; set; }
}
public partial class PropertyAvailability
{
public byte ID { get; set; }
public string Status { get; set; }
public virtual ICollection<PropertyListing> PropertyListings { get; set; }
public PropertyAvailability()
{
PropertyListings = new List<PropertyListing>();
}
}
I am calling this on OnModelCreating
modelBuilder.Entity<PropertyListing>()
.HasRequired(pl => pl.PropertyAvailability)
.WithMany(pa => pa.PropertyListings)
.HasForeignKey(pl => pl.Availability);
It fails with this error,
Invalid column name 'PropertyListing_ID'.
Tutorial I used: http://www.entityframeworktutorial.net/code-first/configure-one-to-many-relationship-in-code-first.aspx
What could be wrong? I know I have screwed up the naming convention EF6 expects, but isn't there a workaround?
P.S: I have seen this question asked from ef3 or so in our SO, but I am unable to find any solution and hence the question.
Add the Column attribute to you class
public partial class PropertyListing
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity), Column("ID")]
public int ID { get; set; }
public string StreetAddress { get; set; }
//the column that links with PropertyAvaibility table PK
public byte? Availability { get; set; }
public bool Status { get; set; }
public virtual PropertyAvailability PropertyAvailability { get; set; }
}
Related
I am developing a C# MVC application. I am using Code First approach to model my database.
My project had the following requirements:
Company Can Have Many Products
Product Can have many Advertisement
Types
Here are model classes (code first solution) to the above mentioned problem.
public class Company
{
public Company()
{
this.Employees = new HashSet<ApplicationUser>();
}
public int ID { get; set; }
[Required]
public string Name { get; set; }
public string Logo { get; set; }
[Display(Name="Company Description")]
public string CompanyDescription { get; set; }
public DateTime Created { get; set; }
public DateTime Updated { get; set; }
public virtual ICollection<ApplicationUser> Employees { get; set; }
public virtual ICollection<Client> Clients { get; set; }
public ICollection<Product> Products { get; set; }
}
public class Product
{
public int ProductID { get; set; }
public DateTime Created { get; set; }
public DateTime Updated { get; set; }
public string ProductName { get; set; }
public int CompanyID { get; set; }
public virtual Company Company { get; set; }
public virtual ICollection<AdvertisementType> AdvertisementTypes { get; set; }
}
public class AdvertisementType
{
public int AdvertisementTypeID { get; set; }
public int ProductID { get; set; }
[Display(Name = "Advertisement Name")]
public string AdvertisementTypeName { get; set; }
public DateTime Created { get; set; }
public DateTime Updated { get; set; }
public virtual Product Product { get; set; }
}
When I try to update the database, after creating the migrations i get the following error:
Introducing FOREIGN KEY constraint 'FK_dbo.AdvertisementTypes_dbo.Products_ProductID' on table 'AdvertisementTypes' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
Could not create constraint or index. See previous errors.
I have been trying solve this problem but unable to find any solution. I don't find any problem with the model classes, nor i think there are any issues with the relationship between the models.
Any suggestions or help will be useful.
EDIT
Here is screenshot of Tables and their relations
in your dbContext you need to turn cascade delete to false if you want to avoid that.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
}
You can initialize your make a List() in Product like you did with Company class...
public class Product
{
public int ProductID { get; set; }
public Product()
{
this.AdvertisementTypes = new List<AdvertisementType>();
}
I have this class :
public class Comment
{
public virtual int Id { get; set; }
public string Body { get; set; }
public DateTime AddDate { get; set; }
[ForeignKey("PostId")]
public virtual Post Post { get; set; }
public int PostId { get; set; }
public virtual bool IsApproved { get; set; }
public virtual int LikeCount { get; set; }
public int? ParentId { get; set; }
public virtual Comment Parent { get; set; }
public ICollection<Comment> Children { get; set; }
public virtual Member Member { get; set; }
public virtual byte[] RowVersion { get; set; }
}
and I use fluent API like this:
this.HasRequired(x => x.Post)
.WithMany(x => x.Comments)
.WillCascadeOnDelete();
this.HasOptional(x => x.Parent)
.WithMany(x=>x.Children)
.HasForeignKey(x=>x.ParentId)
.WillCascadeOnDelete(false);
When I want to run the project, I get this error:
Multiple identity columns specified for table 'Comments'. Only one
identity column per table is allowed. Visual Studio 2013
I just have one primary key in this class and that is Id in first line.
Anyone? I need help
Sometimes EF is unable to correctly order the methods in the DbMigration class. This might happen when you have renamed the PK of some of your entities then add a migration and try to update the database. In order to make it work, go to your migration class (the one that inherits from DbMigration and is auto-generated when you add a new migration) and in the Up() method make all the drop statements precede all other statements.
public override void Up()
{
DropForeignKey();
DropForeignKey();
DropIndex();
DropPrimaryKey();
RenameColumn();
RenameColumn();
RenameIndex();
RenameIndex();
AddForeignKey();
AddForeignKey();
AddPrimaryKey();
}
If the AddPrimaryKey() statement for a table precedes the DropPrimaryKey() statement you will add a primary key before removing the other one and thus you will temporary have two primary keys for that table, and a primary key is an identity column. Therefore you get the "Multiple identity columns specified for table" exception.
The problem is that you most probably have more than one key defined. The one that is defined in your model is Id and the other is defined in your fluent API.
I've tried to reproduce your problem and the code worked perfectly.
Here are my models:
public class Comment
{
public virtual int Id { get; set; }
public string Body { get; set; }
public DateTime AddDate { get; set; }
public virtual Post Post { get; set; }
public int PostId { get; set; }
public virtual bool IsApproved { get; set; }
public virtual int LikeCount { get; set; }
public int? ParentId { get; set; }
public virtual Comment Parent { get; set; }
public ICollection<Comment> Children { get; set; }
public virtual Member Member { get; set; }
public virtual byte[] RowVersion { get; set; }
}
public class Post
{
public int Id { get; set; }
}
public class Member
{
public int Id { get; set; }
}
And here is the code I've used to check if the models are working properly:
var db = new ApplicationDbContext();
db.Comments.Add(new Comment()
{
AddDate = DateTime.Now,
Body = "asd",
IsApproved = true,
LikeCount = 12,
Member = new Member(),
Post = new Post()
});
db.SaveChanges();
My database structure looks like this: Categories table, Questions table and Answers table. Questions have a CategoryID, and Answers have an AnswerID. When trying to access the navigation property "Answers" in my view, I receive the following error:
"'System.Data.Entity.Core.EntityCommandExecutionException' occurred in
EntityFramework.SqlServer.dll but was not handled in user code" Which
is accompanied by:
"Invalid column name 'Question_ID'."
Here's what my classes look like:
public class Category
{
public int ID { get; set; }
public string Text { get; set; }
public string Description { get; set; }
public virtual List<Question> Questions { get; set; }
}
For Question:
public class Question
{
public int ID { get; set; }
public int CategoryID { get; set; }
public string Text { get; set; }
public virtual List<Answer> Answers { get; set; }
public virtual Category Category { get; set; }
}
And for Answer:
public class Answer
{
public int ID { get; set; }
public int QuestionID { get; set; }
public string Text { get; set; }
public int Correct { get; set; }
public virtual Question Question { get; set; }
}
And my Database uses exactly the same field names, with foreign keys applied. I have tried so many variations on the names, including changing the foreign keys to 'Question_ID'and 'Category_ID' but no luck. I've also tried this solution: Code First conventions confusion but it didn't work. Anybody know where I'm going wrong?
I believe the problem is with your answer class. Try this...
public class Answer
{
public int ID { get; set; }
public string Text { get; set; }
public int Correct { get; set; }
[ForeignKey("Question")]
public int QuestionID { get; set; }
public virtual Question Question { get; set; }
}
I wanted to create a relation between two of my models to be 1:0..1 but all i got is a 1..* relation:
public class MedicalExamination
{
public int Id { get; set; }
public DateTime EntryDate { get; set; }
public DateTime ExecutionDate { get; set; }
public DateTime AcceptanceDate { get; set; }
public string Description { get; set; }
public string State { get; set; }
public string Result { get; set; }
public string Comment { get; set; }
public virtual Visit Visit { get; set; }
[Required]
public virtual ExaminationDictionary ExaminationDictionary { get; set; }
}
and my second model:
public class ExaminationDictionary
{
[Key]
public string Code { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public decimal Price { get; set; }
public virtual MedicalExamination MedicalExamination { get; set; }
}
And after i ran it and updated the database i got a relation like this: http://scr.hu/11m6/4eny0
The thing is that i would like it to be 0..1:1 relation. Does anybody know a good solution for this ?
A 1-to-1 or 1-to-0or1 relation in Entity Framework is only possible if both tables share the same primary key.
So for example, your MedicalExamination is presumably the principal entity in the relationship. It has an Id column primary key. Your ExaminationDictionary table needs to have an Id column that is its primary.
You then describe the relationship using Fluent API like so:
modelBuilder.Entity<MedicalExamination>()
.HasOptional(m=>m.ExaminationDictionary)
.WithRequiredPrincipal(d=>d.MedicalExamination);
yesterday I created database in Management Studio and now I want to create it in program using EF Code First.
Here is link to my database: http://s11.postimg.org/6sv6cucgj/1462037_646961388683482_1557326399_n.jpg
And what I did:
public class GameModel
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public DateTime CreationTime { get; set; }
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
public string TotalTime { get; set; }
public DateTime RouteStartTime { get; set; }
public DateTime RouteEndTime { get; set; }
public int MaxPlayersPerTeam { get; set; }
public int CityId { get; set; }
public int CreatorId { get; set; }
[InverseProperty("Id")]
[ForeignKey("CreatorId")]
//public int TeamId { get; set; }
//[ForeignKey("TeamId")]
public virtual UserModel Creator { get; set; }
public virtual CityModel City { get; set; }
//public virtual TeamModel WinnerTeam { get; set; }
}
public class RegionModel
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<CityModel> Cities { get; set; }
}
public class CityModel
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public int RegionId { get; set; }
public virtual RegionModel Region { get; set; }
public virtual ICollection<UserModel> Users { get; set; }
public virtual ICollection<GameModel> Games { get; set; }
}
public class UserModel
{
[Key]
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Login { get; set; }
public string Password { get; set; }
public string Email { get; set; }
public DateTime RegistrationDate { get; set; }
public string FacebookId { get; set; }
public int CityId { get; set; }
public virtual CityModel City { get; set; }
public virtual IEnumerable<GameModel> Games { get; set; }
}
For now I wanted to create 4 tables but I have some problems... I want to make CreatorId in GameModel, but it doesn't work... When i wrote UserId instead of CreatorId it was working ( without [InverseProperty("Id")] and [ForeignKey("CreatorId")]).
This is what i get:
The view 'The property 'Id' 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 ICollection where T is a valid entity type.' or its master was not found or no view engine supports the searched locations.
edit:
I changed it like this:
public int CityId { get; set; }
public int CreatorId { get; set; }
[ForeignKey("CityId")]
public virtual CityModel City { get; set; }
[ForeignKey("CreatorId")]
public virtual UserModel Creator { get; set; }
And there is another problem.
The view 'Introducing FOREIGN KEY constraint 'FK_dbo.UserModels_dbo.CityModels_CityId' on table 'UserModels' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
Could not create constraint. See previous errors.' or its master was not found or no view engine supports the searched locations.
And I have no idea how to solve it.
The InversePropertyAttribute specifies, which navigation property should be used for that relation.
A navigation property must be of an entity type (the types declared in your model, GameModel for example) or some type implementing ICollection<T>, where T has to be an entity type. UserModel.Id is an int, which clearly doesn't satisfy that condition.
So, the inverse property of GameModel.Creator could be UserModel.Games if you changed the type to ICollection<GameModel>, or had to be left unspecified. If you don't specify an inverse property, EF will try to work everything out on its own (in this case it would properly recognize GameModel.Creator as a navigation property, but UserModel.Games would most likely throw an exception, as it is neither an entity type, nor does it implement ICollection<T> with T being an entity type, nor is it a primitive type from a database point of view). However, EF's work-everything-out-by-itself-magic doesn't cope too well with multiple relations between the same entity types, which is when the InversePropertyAttribute is needed.
A quick example that demonstrates the problem:
class SomePrettyImportantStuff {
[Key]
public int ID { get; set; }
public int OtherId1 { get; set; }
public int OtherId2 { get; set; }
[ForeignKey("OtherId1")]
public virtual OtherImportantStuff Nav1 { get; set; }
[ForeignKey("OtherId2")]
public virtual OtherImportantStuff Nav2 { get; set; }
}
class OtherImportantStuff {
[Key]
public int ID { get; set; }
public virtual ICollection<SomePrettyImportantStuff> SoldStuff { get; set; }
public virtual ICollection<SomePrettyImportantStuff> BoughtStuff { get; set; }
}
Here, EF knows that it has to generate 2 FKs from SomePrettyImportantStuff to OtherImportantStuff with the names Id1 and Id2, but it has no way to tell which of the IDs refers to the entity where it was sold from and which is the one it was bought from.
Edit: How to fix the cyclic reference problem
To fix that problem, your context class should override OnModelCreating and configure the foreign keys which shouldn't cascade on delete accordingly, like this:
protected override void OnModelCreating(DbModelBuilder builder)
{
builder.Entity<CityModel>().HasMany(c => c.Users).WithRequired(u => u.City)
.HasForeignKey(u => u.CityId).WillCascadeOnDelete(value: false);
// Add other non-cascading FK declarations here
base.OnModelCreating(builder);
}