At the biginning, I defined the model like this:
public class Category
{
public long CategoryId { get; set;}
public string CategoryName { get; set; }
public virtual ICollection<ContentInfo> Contents { get; set; }
}
Public class Article
{
public int ContentId { get; set; }
public string Content { get; set; }
[ForeignKey("Category")]
public long CategoryId { get; set; }
public virtual Category Category { get; set; }
}
After generating the database from the model with Automatic-Migration, I changed the CategoryId's type from "long" to "int", and update the database with Automatic-Migration again.
This time an exception was throwed, telling me The column "CategoryId" was referenced by Primary key and Foreign Key, so the migration is failed. If i delete the Primary key and Foreign Key manually, everything is ok. but i want the Automatic-Migration to do this for me, can it?
Havent tries such a migration myself, but i recall seeing an option
public class MYMigrationConfiguration : DbMigrationsConfiguration
{
public MyMigrationConfiguration()
{
AutomaticMigrationsEnabled = true;
AutomaticMigrationDataLossAllowed = true; //have you tried this ?
}
Otherwise you may need to do a code based migration for this type of change
You can use the "Sever Explore" and manually manipulate the table structure, e.g., dropping the key constraints, or delete the whole table. And let EF to generate the brand new table definitions.
Related
Is there an easy way to have a setup like this in EF Core?
ProjectEntity
Id
Name
List<Notes>
CustomerEntity
Id
Name
List<Notes>
NotesEntity
Id
Date
Note
Every parent entity would have a one-to-many relation to same child entity. So I can not use normal behavior as
NotesEntity
Id
ParentId
Date
Note
I have some idea to have like above but also add one field that said what the parent entity is, is that the right way to do it or is there a better way? If I use this way I can't use EF Core normal behavior with one-to-many relationship? I need to make more manual work for search / add and so on?
Edit :
Entity Framework multiple parent tables I found this solution, but there I need to make a connection from my child to every parent I use, it could be alot of them.
Did also find a solution like :
BaseEntity
List<Notes>
ProjectEntity:BaseEntity
NotesEntity
Id
BaseEntityId
...
This last solution maybe is the best way to do it if I have alot of parent entities?
[EDIT 220922]
Could [Owned] type has collection of other Items? Or this feature won't work on owned entitys? I guess this behavior isn't supported?
[Owned]
public class Note
{
public int Id { get; set; }
public string Text { get; set; }
public int UserId { get; set; }
public User User { get; set; }
public ICollection<string> Tags { get; set; }
}
I got an error on ICollection-row when I try to add-migration.
Unabel to determine the relationshop represented by navigation ... of
typ 'ICollection' Either manually configure the relationship, or
ignore this property using the '[NotMapped]' attribute.....
Maybe I could have one middleentity like :
public class NoteTagsEntity
{
public int Id { get; set; }
public ICollection<string> Tags { get; set; }
}
And then :
[Owned]
public class Note
{
public int Id { get; set; }
public string Text { get; set; }
public int UserId { get; set; }
public User User { get; set; }
public int NoteTagsId { get; set; }
public NoteTagsId NoteTagsId { get; set; }
}
Edit
I solved the Note functionality with having more FK's, one that point to Id of parent and one FK Id that point to what module that use that particular note. Here I don't have parent - child relation in my entities, I need to do this connection by myself but in this way it's easy to apply more modules that use note's later.
Use Owned Entity Types, and each entity will get its own notes table.
eg
public abstract class Entity
{
public int Id { get; set; }
}
public abstract class EntityWithNotes: Entity
{
public virtual ICollection<Note> Notes { get; set; }
}
[Owned]
public class Note
{
public int Id { get; set; }
public string Text { get; set; }
}
public class Project : EntityWithNotes
{
public string Name { get; set; }
}
public class Customer : EntityWithNotes
{
public string Name { get; set; }
}
creates
CREATE TABLE [Customer_Notes] (
[Id] int NOT NULL IDENTITY,
[CustomerId] int NOT NULL,
[Text] nvarchar(max) NOT NULL,
CONSTRAINT [PK_Customer_Notes] PRIMARY KEY ([CustomerId], [Id]),
CONSTRAINT [FK_Customer_Notes_Customer_CustomerId] FOREIGN KEY ([CustomerId]) REFERENCES [Customer] ([Id]) ON DELETE CASCADE
);
CREATE TABLE [Project_Notes] (
[Id] int NOT NULL IDENTITY,
[ProjectId] int NOT NULL,
[Text] nvarchar(max) NOT NULL,
CONSTRAINT [PK_Project_Notes] PRIMARY KEY ([ProjectId], [Id]),
CONSTRAINT [FK_Project_Notes_Project_ProjectId] FOREIGN KEY ([ProjectId]) REFERENCES [Project] ([Id]) ON DELETE CASCADE
);
I have a problem with the Entity Framework.
public class User : Receiver
{
public User()
{
if (Groups == null)
Groups = new List<Group>();
if (Buddies == null)
Buddies = new List<User>();
}
[Required]
public string PhoneNumber { get; set; }
[ForeignKey("Guid"), JsonIgnore]
public IList<User> Buddies { get; set; }
[ForeignKey("Guid"), JsonIgnore]
public IList<Group> Groups { get; set; }
}
public class Receiver
{
public Receiver()
{
Guid = Guid.NewGuid();
Created = DateTime.Now;
}
[Key]
public Guid Guid { get; set; }
[Required]
public DateTime Created { get; set; }
}
When i try to add a user...
User user = new User
{
Guid = new Guid("8cd094c9-e4df-494e-b991-5cf5cc03d6e3"),
PhoneNumber = "+4991276460"
};
cmc.Receivers.Add(user);
... it ends in follogwing error.
The object of the Type "System.Collections.Generic.List`1[Project.Models.User]" can't be converted to "Project.Models.User".
When i comment out following two lines:
[ForeignKey("Guid"), JsonIgnore]
public IList<User> Buddies { get; set; }
...the programm runs fine.
I hope someone can help me to fix this problem.
Otherwise it runs into an error at this line : cmc.Receivers.Add(user);
In your mapping...
[ForeignKey("Guid"), JsonIgnore]
public IList<User> Buddies { get; set; }
...you specify that User.Buddies is part of a one-to-many relationship and that User.Guid (=Receiver.Guid) is the foreign key in this relationship. But User.Guid is also the primary key, hence it must be unique. As a result a User cannot have a list of Buddies but only a single reference.
The mapping makes no sense but the exception is not very helpful and difficult to understand. (Somehow EF seems to recognize internally that the Buddies cannot be a list with that mapping and wants to cast the list to a single reference. It should detect in my opinion that the mapping is invalid in the first place.)
For a correct one-to-many mapping you need a foreign key that is different from the primary key. You can achieve that by either removing the [ForeignKey] annotation altogether...
[JsonIgnore]
public IList<User> Buddies { get; set; }
...in which case EF will create a default foreign key in the Receivers table (it will be some column with an underscore in its name, but you can rename that with Fluent API if you don't like the default name) or by adding your own foreign key property to the User class:
public Guid? BuddyGuid { get; set; }
[ForeignKey("BuddyGuid"), JsonIgnore]
public IList<User> Buddies { get; set; }
I've got the following EF model:
public class Order
{
public string Id { get; set; }
public IList<OrderLine> Lines { get; set; }
...
}
public class OrderLine
{
public string OrderId { get; set; }
public int Position { get; set; }
...
}
The primary key of OrderLine is made of OrderId and Position:
HasKey(l => new {l.Position, l.OrderId});
Everything worked well so far, until I added this new entity:
public class OrderLineReturn
{
public string Id { get; set; }
...
}
public class OrderLine
{
public string OrderId { get; set; }
public int Position { get; set; }
public IList<OrderLineReturn> LineReturns { get; set; }
...
}
And now I get an error when deleting orders:
DELETE instruction is in conflict with the REFERENCE constraint "FK_dbo.OrderLineReturn_dbo.OrderLine_OrderLine_Position_OrderLine_OrderId"
Could anyone help me understand the issue ?
I am thinking that you need to mark the ILIst property as virtual to enable Lazy loading. Also, I wonder if you need to make a Virtual Order Property in OrderLine instead of having the OrderID reference.
I'm not sure if I'm correct, but I think that you would have the same problem if you tried to delete an Order without deleting first it's OrderLines.
The problem is that OrderLineReturn will have a reference to the OrderLine, and when you delete the OrderLine without first deleting the OrderLineReturn it will give you that error.
I think you can enable cascade deleting...but it's always a risk.
Regards,
I have an app that was created using EF. The problem is that I noticed some extraneous foreign keys columns created in one of the tables. Dropping these columns causes an [SqlException (0x80131904): Invalid column name 'Material_Id' error.
Here is a simplified version of the class structure...
public class Hazard
{
public int Id { get; set; }
public string Name { get; set; }
}
public abstract class HazardAnalysis
{
public int Id { get; set; }
public int HazardId { get; set; }
public virtual Hazard Hazard { get; set; }
}
public class ProductHazard : HazardAnalysis
{
public int ProductId { get; set; }
public virtual Product Product { get; set; }
}
The table that was generated looked like this...
dbo.Hazards
Id int
Name string
Product_Id int
Since the relationship between ProductHazards and Hazards is 1:many, the Product_Id field should not be there. Dropping this column generates the Invalid column name 'Product_Id' error.
I've scoured the model for hours and can't find any valid reason for this column to exist.
Is there any way to update the model after manually dropping a column? I obviously don't want to drop and recreate the database.
I've also noticed that the productId of the current product is inserted in the dbo.Hazards Product_Id table whenever a new ProductHazard is created. Since there is a many-to-one relationship between ProductHazards and Hazards, when a new ProductHazard is created, the Product_Id field is updated with the ProductId of the new ProductHazard, which seems bizarre.
Any advice would be greatly appreciated.
Here is the DbSet code:
public DbSet<Hazard> Hazards { get; set; }
public DbSet<HazardAnalysis> HazardAnalyses { get; set; }
and also...
modelBuilder.Entity<HazardAnalysis>()
.HasRequired(e => e.Hazard)
.WithMany()
.HasForeignKey(e => e.HazardId)
.WillCascadeOnDelete(false);
You need to define the many part of the relationship. In this case, you need to add a collection property to your Hazard object, like below:
public class Hazard
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<HazardAnalysis> HazardAnalyses { get; set; }
}
When performing a delete of a one-many relationship without exposing the foreign key, EF deletes the parent record and tries to null the foreign key on the child records. This of course causes an error because the foreign key is not nullable. Adding the foreign key to the child class overrides this behavior, but I'd rather not expose it.
For example given the following two classes, I'd prefer not to have JobId as a property of the Project class.
public class Job : ModelBase
{
[Required]
[StringLength(100)]
public string Company { get; set; }
[Required]
[StringLength(100)]
public string JobTitle { get; set; }
public ICollection<Project> Projects { get; set; }
}
public class Project : ModelBase
{
[Required]
[StringLength(100)]
public string Name { get; set; }
[Required]
public string Summary { get; set; }
public int JobId { get; set; }
}
Is there a way to enable cascading deletes in EF Code First without exposing the foreign key on the many side of the relationship?
Yup! Remove JobId and add the following:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Job>().HasMany(j => j.Projects).WithRequired();
}
In the database, this will add a cascading delete in the PK/FK relationship.
(I'm assuming that your ModelBase has an integer Id =)