I have searched for empty migrations, and those solutions (ie. clean solution/build) have not worked for me. I am wondering if there might be something more going on.
I have an entity...
public class Term
{
public int Id { get; set; }
public string Title { get; set; }
public virtual Organization Organization { get; set; }
}
When this entity is built in the database, it creates a column "Organization_Id". The Organization entity is straight forward. Nothing weird. Per usual when running add-migration, it also creates a foreign key constraint and index on the "Organization_Id" pointing towards the Organization entity.
We are dropping the link to the Organization entity. So, naturally we delete the virtual property and then run add-migration. I expect to see the dropping of the "Organization_Id" column, but it is an empty migration class.
public partial class termremoveorg : DbMigration
{
public override void Up()
{
}
public override void Down()
{
}
}
After trying a hundred different things, I am at a loss. I even manually added dropping the column by manually setting up...
public partial class termremoveorg : DbMigration
{
public override void Up()
{
DropIndex("dbo.Terms", new[] { "Organization_Id" });
DropForeignKey("dbo.Terms", "Organization_Id", "dbo.Organizations");
DropColumn("dbo.Terms", "Organization_Id");
}
public override void Down()
{
AddColumn("dbo.Terms", "Organization_Id", c => c.Int());
AddForeignKey("dbo.Terms", "Organization_Id", "dbo.Organizations", "Id");
CreateIndex("dbo.Terms", "Organization_Id");
}
}
But when I run the update-database, the database table successfully has the "Organization_Id" column deleted. But I get the following error when the Seed() method gets to the point in the code where a few Term objects are inserted into the database (they do not reference any link to Organization records)...
System.Data.SqlClient.SqlException: Invalid column name 'Organization_Id'.
Thanks for any insight or help.
Update #1
Per requested, here is the Organization class.
public class Organization
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Term> Terms { get; set; }
}
Looking closer at this code I realized there was a property pointing back to Terms that was not removed before running the add-migration.
Trying it out, I removed this property as well and the add-migration ran as expected and successfully.
Due to 1 : M relationship with the Organization : Terms where you have to remove both end points.In other words you have to remove public virtual Organization Organization { get; set; } on the Term and public virtual ICollection<Term> Terms { get; set; } on the Organization.Then you will not have any issue with the Migration script.
Related
I have a EF-Core Code-First apporach. Im Saving a HolderModel into a Database which contains a ID and a List of Models.
On Saving everything works fine. The Struktur is correct and all data is in the Database. But if i load the data back into my code, the List of Models is gone.
Im a bit confused as usally EF did everything by him self.
Am i missing something for EF-Core ?
Here is the codesnippet:
DB-Context:
public DbSet<FinancialStateHolderModel> States { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder builder)
{
builder.UseSqlServer(
#"Server=.\;Database=Stock;User Id=dbuser;Password=dbuser");
builder.EnableSensitiveDataLogging(true);
}
HolderModel:
public class FinancialStateHolderModel
{
[Key]
public String Symbol { get; set; }
public List<FinancialStatementModel> Financials { get; set; }
}
Models:
public class FinancialStatementModel
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public DateTime Date { get; set; }
}
Please check Loading Related Data in Entity Framework.
You're looking for
Eager loading - the related data is loaded from the database as part
of the initial query
In your case(example not exact syntax because I don't know what your call looks like)
should be context.FinancialStateHolders.Include(x=> x.FinancialStatements)
Let's start with one-to-many relationship:
public sealed class MyContext : DbContext
{
protected override void OnModelCreating(ModelBuilder builder)
{
builder.Entity<Slave>()
.HasOne(typeof(Master))
.WithMany() // *
.HasForeignKey(nameof(Slave.ForeignField));
}
}
So I declare that per one record in Master table I can have multiple records in Slave table. When I run EF tools to build migration this is accepted and works fine.
But when I change the line marked with asterisk to:
.WithOne()
in order to build one-to-one relationship building migration fails with error:
You are configuring a relationship between 'Slave' and 'Master' but
have specified a foreign key on 'ForeignField'. The foreign key must
be defined on a type that is part of the relationship.
I don't get it, just a second ago the given field (property in C# terms) was OK, and now EF claims it cannot find it?
Whad do I miss? How to make EF happy?
Record types are as follows -- please note there are no navigational properties.
internal sealed class Slave
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public Guid InstanceId { get; set; }
public Guid ForeignField { get; set; }
}
internal sealed class Master
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public Guid Id { get; set; }
}
For the time being I solved this using raw SQL, it works, but I am still curious what is wrong here.
Thanks to #AminGolmahalle answer, my curiosity was triggered why and can I use HasForeignKey in generic form. This lead me to finding out that I cannot, but what more is that WithOne and WithMany are not 1:1 replacements of each other. Both lead to different overloads.
So the first version one-to-many worked because I was hitting the right overload, the second didn't, because I was passing incorrect arguments. The correct version is:
builder.Entity<Slave>()
.HasOne(typeof(Master))
.WithOne()
.HasForeignKey(nameof(Slave), nameof(Slave.ForeignField)); // changed
the first argument has to be name of the slave table (again).
But is is even better to switch to generic version (see last comment under accepted answer) and avoid possibility of such "stupid" mistake in the first place.
Below code just sample for relation one to one:
public class Author
{
public int AuthorId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public AuthorBiography Biography { get; set; }
}
public class AuthorBiography
{
public int AuthorBiographyId { get; set; }
public string Biography { get; set; }
public DateTime DateOfBirth { get; set; }
public string PlaceOfBirth { get; set; }
public string Nationality { get; set; }
public int AuthorRef { get; set; }
public Author Author { get; set; }
}
You Can Use FluentApi For Relation In EntityFramework:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Author>()
.HasOne(a => a.Biography)
.WithOne(b => b.Author)
.HasForeignKey<AuthorBiography>(b => b.AuthorRef);
}
Using FluentApi is much better than DataAnnotaion.
FluentApi In Asp Core
I Suggest To You Read About FluentValidation
Refer this link, i think this will do
https://www.learnentityframeworkcore.com/configuration/one-to-one-relationship-configuration
I got into some trouble with EntityFramework and the following datamodel (see simplified diagram).
The Matter object can be thinked as the "main container". There are Bill and BillRecord. There is a one-to-many association from Bill to BillRecord. Precisely, a Bill can reference many BillRecord (possibly 0) and a BillRecord can be referenced to at most one bill.
1) I want to be able to delete a BillRecord but it should not delete the Bill, if there is an association (that is why I did not set a OnCascadeDelete For Bill on BillRecords entity). Similarly, if I delete a Bill I do not want to delete the BillRecord that may be associated with.
2) However, when I delete a Matter I want everything to disappear: the Matter, Bill and BillRecords.
With the following code, I manage to have 1) right and 2) works if there is no BillRecord associated to a Bill, if there is one I get the following error.
System.Data.SqlServerCe.SqlCeException: The primary key value cannot be deleted because references to this key still exist. [ Foreign key constraint name = FK_dbo.BillRecordDboes_dbo.BillDboes_BillId ]
Here is my entities and my logic for OnModelCreating
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<MatterDbo>().HasMany<BillRecordDbo>(s => s.BillRecordDbos)
.WithRequired(s => s.Matter).HasForeignKey(s => s.MatterId).WillCascadeOnDelete(true);
modelBuilder.Entity<MatterDbo>().HasMany<BillDbo>(s => s.BillDbos)
.WithRequired(s => s.Matter).HasForeignKey(s => s.MatterId).WillCascadeOnDelete(true);
}
public class MatterDbo
{
public MatterDbo()
{
BillDbos = new List<BillDbo>();
BillRecordDbos = new List<BillRecordDbo>();
}
public Guid Id { get; set; }
public virtual List<BillDbo> BillDbos { get; set; }
public virtual List<BillRecordDbo> BillRecordDbos { get; set; }
}
public class BillRecordDbo
{
public Guid Id { get; set; }
public Guid MatterId { get; set; }
public virtual MatterDbo Matter { get; set; }
public Guid? BillId { get; set; }
public virtual BillDbo Bill { get; set; }
}
public class BillDbo
{
public BillDbo()
{
BilledRecords = new List<BillRecordDbo>();
}
public Guid Id { get; set; }
public virtual List<BillRecordDbo> BilledRecords { get; set; }
public Guid MatterId { get; set; }
public virtual MatterDbo Matter { get; set; }
}
Of course, when deleting a Matter I could check and remove all the associations of Bill and BillRecords manually but I think it would be a wrong usage of EF.
I am using EntityFramework 6.0 and SQL CE targetting .NET 4.0
Thank you very much.
If you really need BillRecord to remain in the database if its parent, Bill entity, is deleted, then you have to set the parent property to null before deleting the parent. However, having a nullable FK in the database is often a sign there might be a better db design solution.
I've added a new property in my entity and ran the command to generate a new migration, but the generated migration contains nothing. Looks like EF did not detect the column add. Is there something else I need to do in order to get the column added in the migration? This is my class:
public class Group
{
public int Id { get; set; }
public int OrganizerId { get; set; }
public string Name { get; set; }
public string ImageUrl { get; set; }
public bool IsOnline { get; set; }
public virtual User Organizer { get; set; }
public virtual ICollection<GroupParticipation> GroupParticipations { get; set; }
public virtual ICollection<Question> Questions { get; set; }
public virtual ICollection<Subject> Subjects{ get; set; }
}
I have isolated the property I'm trying to add, which is "IsOnline". After adding it to the class and compiling the project, I run the following command:
Add-Migration AddGroupIsOnline
It correctly generated a new migration but here's how the migration looks like:
public partial class AddGroupIsOnline : DbMigration
{
public override void Up()
{
}
public override void Down()
{
}
}
The Up and Down does nothing. It should have added my property, is my assumption correct?
Any idea on what may be happening?
Thanks for all the help!
Ok, so I found the "problem". Basically an automatic migration has happened in some moment after I added the IsOnline property in my Group class. Therefore when I ran Add-Migration AddGroupIsOnline, no changes were detected (because it was already changed by automatic migration).
I ended up finding the answer by looking at my database table and the column was already there. Then I looked at the migration table, that gets created once DB Migrations are activated, and I found the following line:
Then I removed the IsOnline column, deleted the Automatic Migration record from the database and then re-ran:
Add-Migration AddGroupIsOnline
And here is the result:
public partial class AddGroupIsOnline : DbMigration
{
public override void Up()
{
AddColumn("dbo.Groups", "IsOnline", c => c.Boolean(nullable: false));
}
public override void Down()
{
DropColumn("dbo.Groups", "IsOnline");
}
}
So my self tip here is: if nothing is shown in the migration, there is nothing to be migrated. Verify the database and the automatic migrations in the [__MigrationHistory] table.
I am having problems with my model and trying to delete records. I have reduced it to try and show the issue I am having
I have a entity called CollectedBags with an Id and name.
I then have a entity called BankingRun which contains a list of CollectedBags
public virtual List<CollectedBags> Bags { get; set; }
This model automatically adds a relationship between the two, and in the database it adds a column to collectedbags to reference the BankingRun.
The problem occurs when I want to delete the BankingRun without affecting the CollectedBags table at all. A CollectedBags record doesn't always belong to a BankingRun.
Anything I try to delete a record results in a conflict between the two tables obviously, but my lack of knowledge with entity framework is leaving me stuck without writing some SQL to physically remove the Banking Run id in CollectedBags
public class CollectedBags
{
public long CollectedBagsId { get; set; }
public string Name { get; set; }
}
public class BankingRun
{
public long BankingRunId { get; set; }
public DateTime DateTimeVisited { get; set; }
public virtual List<CollectedBags> Bags { get; set; }
}
I am then trying to delete a BankingRun after its been created with multiple CollectedBags
With Fluent API use this code:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.HasOptional(a => a.UserDetail)
.WithOptionalDependent()
.WillCascadeOnDelete(false);
}
This is just an illustration, but the important thing here is the .WillCascadeOnDelete(false);
It will prevent that when you delete one entity all others related get deleted as well, basically.