I have a Property table and I have a Property Ratios table.
Properties may or may not have Ratio data.
I am attempting to create a link between the 2 tables but I am getting the error when trying to do an "add-migration".
These are my tables:
public class PropertyForSale
{
[Key]
public int Id { get; set; }
[Index("IX_pid", IsClustered = false, IsUnique = true, Order = 1), MaxLength(15)]
public string pid { get; set; }
[MaxLength(25)]
public string Status { get; set; }
public virtual PropertyRatios PropertyRatios { get; set; }
}
public class PropertyRatios
{
[Key, MaxLength(15)]
public string pid { get; set; }
public float Zest_List_Price_Diff { get; set; }
[Index]
public DateTime LastUpdated { get; set; }
}
And here is my fluent API configuration:
modelBuilder.Entity<PropertyForSale>()
.HasOptional(o => o.PropertyRatios)
.WithOptionalPrincipal()
.Map(o => o.MapKey("pid"));
I am getting the error:
One or more validation errors were detected during model generation:
pid: Name: Each property name in a type must be unique. Property name 'pid' is already defined.
I want the tables linked via the "pid".
Can anyone see what I am doing wrong?
Remove public string pid { get; set; } from PropertyForSale
Renaming parameters just to make it more readable.
AddMigration will do this for you
public class PropertyForSale
{
[Key]
public int Id { get; set; }
[MaxLength(25)]
public string Status { get; set; }
public virtual PropertyRatios PropertyRatios { get; set; }
}
public class PropertyRatios
{
[Key, MaxLength(15)]
public string pid { get; set; }
public float Zest_List_Price_Diff { get; set; }
[Index]
public DateTime LastUpdated { get; set; }
}
This will create pid as foreign key in PropertyForSale.
Related
I am creating a blog of sorts with C#/.NET 4.5 framework using EF code-first migrations.
Things have been going well up until adding a third relationship into my main class.
I have a "story" class (kind of like a "post" for a blog) where I have the author as the user who's logged in (set in the controller), a title, some content, the date it was created, and a genre and type of story.
public class Story
{
public int Id { get; set; }
public string AuthorId { get; set; }
public virtual ApplicationUser Author { get; set; }
[Required]
[StringLength(50)]
public string Title { get; set; }
[Required]
[MinLength(100), MaxLength(5000)]
public string Content { get; set; }
[Required]
public int GenreId { get; set; }
public Genre Genre { get; set; }
[Required]
public int StoryTypeId { get; set; }
public StoryType StoryType { get; set; }
public DateTime CreatedAt { get; set; }
}
I added storytypes as a property to the story. StoryType links to the StoryType model:
public class StoryType
{
public int Id { get; set; }
public string Name { get; set; }
}
I made sure to add my dbset to my application db context:
public DbSet<Genre> Genres { get; set; }
public DbSet<Story> Stories { get; set; }
public DbSet<StoryType> StoryTypes { get; set; }
I pretty much followed the same steps I used to create the relationship between the story and genre (which worked fine). Before I start building the StoryType controllers, I went into package-console and ran:
add-migration
that returned:
public partial class CreateTypeTable : DbMigration
{
public override void Up()
{
CreateTable(
"dbo.StoryTypes",
c => new
{
Id = c.Int(nullable: false, identity: true),
Name = c.String(),
})
.PrimaryKey(t => t.Id);
AddColumn("dbo.Stories", "StoryTypeId", c => c.Int(nullable: false));
CreateIndex("dbo.Stories", "StoryTypeId");
AddForeignKey("dbo.Stories", "StoryTypeId", "dbo.StoryTypes", "Id", cascadeDelete: true);
}
public override void Down()
{
DropForeignKey("dbo.Stories", "StoryTypeId", "dbo.StoryTypes");
DropIndex("dbo.Stories", new[] { "StoryTypeId" });
DropColumn("dbo.Stories", "StoryTypeId");
DropTable("dbo.StoryTypes");
}
}
Glancing over it, I didn't see an issue, then ran:
update-database
in package-console.
Which returned:
Error Number:547,State:0,Class:16
The ALTER TABLE statement conflicted with the FOREIGN KEY constraint "FK_dbo.Stories_dbo.StoryTypes_StoryTypeId". The conflict occurred in database "aspnet-HiRatik.Stories-20180724043630", table "dbo.StoryTypes", column 'Id'.
I'm not sure what went wrong here. I did the same process with the Genre relationship and it worked. I didn't see a difference in the two.
because the StoryTypeId in the class Story dosen't accept null so you need to make the StoryTypeId nullable :
public class Story
{
public int Id { get; set; }
public string AuthorId { get; set; }
public virtual ApplicationUser Author { get; set; }
[Required]
[StringLength(50)]
public string Title { get; set; }
[Required]
[MinLength(100), MaxLength(5000)]
public string Content { get; set; }
[Required]
public int GenreId { get; set; }
public Genre Genre { get; set; }
public int? StoryTypeId { get; set; }
public StoryType StoryType { get; set; }
public DateTime CreatedAt { get; set; }
}
or you create first the table StoryType and you add elements to it and then add the StoryTypeId with default value:
public class Story
{
public int Id { get; set; }
public string AuthorId { get; set; }
public virtual ApplicationUser Author { get; set; }
[Required]
[StringLength(50)]
public string Title { get; set; }
[Required]
[MinLength(100), MaxLength(5000)]
public string Content { get; set; }
[Required]
public int GenreId { get; set; }
public Genre Genre { get; set; }
[[DefaultValue(1)]]
public int StoryTypeId { get; set; }
public StoryType StoryType { get; set; }
public DateTime CreatedAt { get; set; }
}
in this case you must update the database after creating StoryType and the after adding the StoryTypeId to the class Story
You can make the foreign key nullable by using a sign ?, like this: int?.
In my case, I was getting this because there was data in the table on which I was creating the foreign key that's why I was getting this error. And as we know foreign key is nullable.
I'd like to set one bool property in my controller and save it to the database. EF throws an error about other properties that are not even modified.
The association between entities 'User' and 'RequestDetail' with the
key value 'System.InvalidOperationException: The association between
entities 'User' and 'RequestDetail' with the key value '{Id: 40}' has
been severed but the relationship is either marked as 'Required' or is
implicitly required because the foreign key is not nullable. If the
dependent/child entity should be deleted when a required relationship
is severed, then setup the relationship to use cascade deletes.
If I call my method with an additional parameter it has to change one RequestDetail record's RequestSent property and that is working great.
But calling the method without this additional parameter it has to change this property on more than one RequestDetail records. And this is where it throws the error. I don't modify anything associated with User.
If it has to do more records at once it throws this error. Even if I rewrite the foreach into a while with FirstOrDefaults() and immediate SaveChanges() it throws error on the second round.
My method:
var head = await _ctx.RequestHeads.FirstOrDefaultAsync(x=>x.Id == d.Id);
if (!d.DetailId.HasValue) {
var details = _ctx.RequestDetails.Include(x=>x.BuyerUser)
.Where(x=>x.RequestHeadId == head.Id);
//not working, always throws an error if it has to modify more than one record
await details.ForEachAsync(detail => {
detail.RequestSent = true;
});
} else {
var detail = head.Details.FirstOrDefault(x=>x.Id == d.DetailId.Value); //works ok, always
detail.RequestSent = true;
}
await _ctx.SaveChangesAsync();
My models:
public class RequestHead
{
[Key, MaxLength(15)]
public string Id { get; set; }
public DateTime CreateDate { get; set; }
public int CreateUserId { get; set; }
[ForeignKey("CreateUserId")]
public User CreateUser { get; set; }
public DateTime? AcceptDate { get; set; }
public int? AcceptUserId { get; set; }
[ForeignKey("AcceptUserId")]
public User AcceptUser { get; set; }
public DateTime? CloseDate { get; set; }
public int? CloseUserId { get; set; }
[ForeignKey("CloseUserId")]
public User CloseUser { get; set; }
public int? CloseReason { get; set; }
public bool IsArchive { get; set; }
[MaxLength(8)]
public string OrganizationCode { get; set; }
[ForeignKey("OrganizationCode")]
public Organization Organization { get; set; }
public virtual ICollection<RequestDetail> Details { get; set; }
public virtual ICollection<RequestAttachment> Attachments { get; set; }
}
public class RequestDetail
{
[Key]
public int Id { get; set; }
public string RequestHeadId { get; set; }
[ForeignKey("RequestHeadId")]
public RequestHead RequestHead { get; set; }
[MaxLength(20)]
public string ProductCode { get; set; }
[ForeignKey("ProductCode")]
public Product Product { get; set; }
public string ProductName { get; set; }
public bool NoProductCode { get; set; }
public string Description { get; set; }
public DateTime CreateDate { get; set; }
public int CreateUserId { get; set; }
[ForeignKey("CreateUserId")]
public User CreateUser { get; set; }
public DateTime? DelegateDate { get; set; }
public int? DelegateUserId { get; set; }
[ForeignKey("DelegateUserId")]
public User DelegateUser { get; set; }
public int? BuyerUserId { get; set; }
[ForeignKey("BuyerUserId")]
public User BuyerUser { get; set; }
public bool RequestSent { get; set; }
public virtual ICollection<RequestAttachment> Attachments { get; set; }
}
Context:
modelBuilder.Entity<RequestHead>()
.HasOne(r=>r.CreateUser)
.WithOne().OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<RequestHead>()
.HasMany(r => r.Details)
.WithOne(x=>x.RequestHead)
.HasForeignKey(rd => rd.RequestHeadId);
modelBuilder.Entity<RequestDetail>()
.HasOne(r=>r.CreateUser)
.WithOne().OnDelete(DeleteBehavior.Restrict);
The solution was to change RequestDetail<=>User relations from WithOne() to WithMany(). Although the error message is somewhat misleading, a possible explanation from #IvanStoev is the following:
I guess with one-to-one the code expects single record, so when the
second record with the same FK comes in, they get confused and decided
that the record is deleted
A quick question for masters.
I got 2 EF model classes:
public class School
{
public int Id { get; set; }
[DisplayName("School")]
public string Name { get; set; }
public List<Teacher> Teachers { get; set; }
public List<Note> Notes { get; set; }
}
public class Teacher
{
public int Id { get; set; }
[DisplayName("Öğretmen")]
public string Name { get; set; }
public int SchoolId { get; set; }
public School School { get; set; }
public List<Note> Notes { get; set; }
}
Basically I want to create an one to many relationship in code-first.
But when I try to do that, I get this error:
Introducing FOREIGN KEY constraint 'FK_dbo.Teachers_dbo.Schools_SchoolId' on table 'Teachers' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
Where have I made a mistake?
EDIT
public class Note
{
public int Id { get; set; }
[Required,DisplayName("Başlık"), StringLength(50)]
public string Title { get; set; }
[Required,DisplayName("Açıklama"), StringLength(4000)]
public string Description { get; set; }
public string File { get; set; }
public DateTime UploadDate { get; set; }
public bool IsApproved { get; set; }
public int SchoolId { get; set; }
public int OwnerId { get; set; }
public int TeacherId { get; set; }
//Keys
public School School { get; set; }
public Teacher Teacher { get; set; }
public List<Comment> Comments { get; set; }
}
I didnt get any error for this Model and Keys..
Remove the relationship from Note to School and vice versa. You could get the school by the teacher that has a relationship to the note.
It will produce your issue.
When I'm using the following code, the tables are generated successfully with the Primary key and Foreign Key relations.
[Table("tblDepartments")]
public class DepartmentModel
{
[Key]
public int DepartmentID { get; set; }
public string Name { get; set; }
public string Location { get; set; }
public ICollection<EmployeeModel> Employees { get; set; }
}
[Table("tblEmployees")]
public class EmployeeModel
{
[Key]
public int EmployeeID { get; set; }
public string Name { get; set; }
public string Gender { get; set; }
public string City { get; set; }
public virtual DepartmentModel DID { get; set; }
}
But when I use the following Code, I'm Getting error:
[Table("tblDepartments")]
public class DepartmentModel
{
[Key]
public int DepartmentID { get; set; }
public string Name { get; set; }
public string Location { get; set; }
public ICollection<EmployeeModel> Employees { get; set; }
}
[Table("tblEmployees")]
public class EmployeeModel
{
[Key]
public int EmployeeID { get; set; }
public string Name { get; set; }
public string Gender { get; set; }
public string City { get; set; }
[ForeignKey("DeptID")]
public virtual DepartmentModel DID { get; set; }
}
ERROR:
The ForeignKeyAttribute on property 'DID' on type
'MvcApplication1.Models.EmployeeModel' is not valid. The foreign key
name 'DeptID' was not found on the dependent type
'MvcApplication1.Models.EmployeeModel'. The Name value should be a
comma separated list of foreign key property names.
Please Help. Thanks in advance.
The problem is with your EmployeeModel as you are missing departmentid field in your table as suggested by Gert. you can use the below for EmployeeModel
[Table("tblEmployees")]
public class EmployeeModel
{
[Key]
public int EmployeeID { get; set; }
public string Name { get; set; }
public string Gender { get; set; }
public string City { get; set; }
public int DeptID { get; set; } //<-- You forgot to add this
[ForeignKey("DeptID")]
public virtual DepartmentModel DID { get; set; }
}
Put the foreign key as a property inside your model then have the navigation property point to it.
public class EmployeeModel
{
[Key]
public int ID { get; set; }
public int DeptID { get; set; }
public string Name { get; set; }
public string Gender { get; set; }
public string City { get; set; }
[ForeignKey("DeptID")]
public virtual DepartmentModel DID { get; set; }
}
In '[ForeignKey("DeptID")]' you need to have the property DeptID in the model.
If you don't want it but just the name DeptID on the foreign key field you need to use fluent interface to configure the relationship i.e.
HasOptional(t => t.DID)
.WithMany()
.Map(d => d.MapKey("DeptID"));
I use Entity Framework 6.1 in ASP.NET MVC.
My model is :
public class Article
{
[Key]
public int Id { get; set; }
[Required]
public string Name { get; set; }
public double Price { get; set; }
[InverseProperty("Article")]
public virtual ICollection<FormulaItem> FormulaItem { get; set; }
}
public class FormulaItem
{
[Key]
[Column(Order = 0)]
public int Id { get; set; }
[ForeignKey("IdMaster")]
public virtual Formula Formula { get; set; }
public int IdMaster { get; set; }
[ForeignKey("IdArticle")]
public virtual Article Article { get; set; }
public int IdArticle { get; set; }
public string Comment { get; set; }
public int Count { get; set; }
}
public class Formula
{
[Key]
[Column(Order = 0)]
public int Id { get; set; }
public FormulaMode Mode { get; set; }
// Wen add this line I get error
//[ForeignKey("IdArticle")]
//public virtual Article Article { get; set; }
//public int? IdArticle { get; set; }
public string Comment { get; set; }
public virtual IList<FormulaItem> Items { get; set; }
public Formula()
{
Items = new List<FormulaItem>();
}
}
This sample works fine, but when add the new poco:
// When I add this line in class formula I get error
[ForeignKey("IdArticle")]
public virtual Article Article { get; set; }
public int? IdArticle { get; set; }
to class Formula I get error:
Formula_Items_Source_Formula_Items_Target: : The number of properties in the Dependent and Principal Roles in a relationship constraint must be identical
Consider using FluentAPI as it is more user-friendly:
modelBuilder.Entity<FormulaItem>()
.HasOptional(b => b.Article )
.WithMany(a => a.FormulaItem);
And in your case you must be missing another InverseProperty attribute:
[InverseProperty("FormulaItem")]
public virtual Article Article { get; set; }
I add:
modelBuilder.Configurations.Add(new FormulaConfig());
public class FormulaConfig : EntityTypeConfiguration<Formula>
{
public FormulaConfig()
{ // one-to-many
this.HasRequired(x => x.Article)
.WithOptional(x=>x.Formula)
.WillCascadeOnDelete();
}
}
but get error :
Article_Formula_Target: : Multiplicity is not valid in Role 'Article_Formula_Target' in relationship 'Article_Formula'. Because the Dependent Role properties are not the key properties, the upper bound of the multiplicity of the Dependent Role must be '*'.