I have a class:
public class Foo {
public Guid Id { get; set; }
public Bar Child { get; set; }
}
When I insert into Foo via context.Foos.Add(myFoo), a Bar is being inserted into the database if it is not null.
How can I prevent this from happening? Do I have to set Child to null prior to inserting into the context?
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've created an abstract class with some base properties:
public abstract class BaseModel
{
public BaseWishModel()
{
}
[Key]
public int Id { get; set; }
public virtual string Title { get; set; }
public bool IsPublished { get; set; }
public bool IsSpam { get; set; }
}
My item class:
public class PrivateItem : BaseModel
{
[NotMapped]
public string PurposesIds { get; set; }
}
My OnModelCreating method:
modelBuilder.Entity<BaseModel>()
.Map<PrivateItem>(r => r.Requires("Discriminator").HasValue((int)Enums.Type.Private))
.ToTable("Items");
When I save the data it's generates next sql:
INSERT [dbo].[Items]([Title], [IsPublished], [ShortDescription1], [ShortDescription2], [Discriminator])
I don't know why it's generates ShortDescription1 and ShortDescription1
As, according to your comment, you have other classes inheriting from BaseModel, and with no other configuration from you, EF uses TPH by default.
Basically this leads to a single table for all the classes hierarchy.
As all classes of the hierarchy are persisted in the same table when an insert, for one class, is done, all columns (of the hierarchy) are populated. The non used by the class columns are populated by null or default value.
This bring the ShortDescription1 and ShortDescription2 in your insert query.
We have the following set of objects.
public class Form
{
public int FormId { get; set; }
public DateTime DateCreatedOn { get; set; }
public string Status { get; set; }
}
// This is using TPT inheritance from Form
[Table("FormA")]
public class FormA : Form
{
public string ExtraInfoA { get; set; }
public virtual ICollection<Child> Children
}
// This is using TPT inheritance from Form
[Table("FormB")]
public class FormB : Form
{
public string ExtraInfoB { get; set; }
public virtual ICollection<Adult> Adults
}
public class Person
{
public int PersonId { get; set; }
public int FormId
public DateTime DateOfBirth { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
// This is using TPH inheritance from Person
public class Adult : Person
{
public int HowManyCars { get; set; }
public string NationalInsuranceNo { get; set; }
[ForeignKey("FormId")]
public virtual FormB FormB { get; set; }
}
// This is using TPH inheritance from Person
public class Child : Person
{
public int HowManyToys { get; set; }
public string SchoolName { get; set; }
[ForeignKey("FormId")]
public virtual FormA FormA { get; set; }
}
This creates 3 tables for the forms Form, FormA, and FormB, all with the appropriate fields in them. It also creates 1 table for Person.
The problem is When we rely on the convention and don't specify the ForeignKey attribute the Person table contains 2 additional foreign key columns.
However when we do specify the ForeignKey attribute (as in the code above) we get the following error message.
`The foreign key component 'FormId' is not a declared property on type 'Child'. Verify that it has not been explicitly excluded from the model and that it is a valid primitive property.`
FormId is definitely a property of Child so I'm not sure what is going wrong.
Our real world situation is a lot more complicated that the situation above so I'd like to get it right now rather tham have multiple foreign keys.
Any help is very much appreciated.
You cannot define foreign key in the parent entity and navigation property in the child entity. They must both be defined in the same entity. What you are trying to do is even not valid in the database because you cannot have conditional foreign key constraint on the column - constraints to both FormA and FormB will be applied for every record and you will never be able to insert any record (because it would always violate constraint to FormA or FormB).
In short: You need either single navigation property in parent or separate foreign key for every child.
I want to create a 1 to 1 relationship by code first, below is my code,
class Person
{
public int id { get; set; }
public string Name { get; set; }
public virtual PersonDetail detail { get; set; }
}
class PersonDetail
{
public int id { get; set; }
public double Height { get; set; }
public double Weight { get; set; }
public virtual Person person { get; set; }
}
class EFTest : DbContext
{
public DbSet<Person> personSet { get; set; }
public DbSet<PersonDetail> detailSet { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Person>().HasRequired(x => x.detail).WithRequiredPrincipal(x => x.person);
}
}
But I still can insert a person without person detail. I'm trying to create a 1 to 1 relationship in model first, it works well, if I insert one end without the other end, there will be an exception thrown. Why code first with the code above create a 1 to 0..1 relationship?
Anyone can help?
That is possible only if both Person and PersonDetail will be mapped to the same table (the mapping technique is called Table Splitting) because strict 1:1 means that you cannot insert Person without existing PersonDetail but you also cannot insert PersonDetail without existing Person => you cannot insert either of them because the dependency will be always missing (remember each record has its own insert command and database check the integrity after each command not after transaction).
Only when you use table splitting EF will create single insert command containing data from both entities. In your entity model it will look like two entities with 1:1 mapping but in database it will be single table.
Say you have an order class with an order status, I want to declare the OrderStatusId inside the OrderStatus class. However, no foreign key relationship is set-up by default. If I use [ForeignKey] attribute on the column it seems to demand a navigation property which I don't want as this would mean having to carry out joins on the navigation property in all of my queries just to check the status.
How do I accomplish this in EF codefirst? Define a property as a foreign key without using a navigation property.
public class Order
{
public int OrderId;
public int OrderStatusId;
// properties...
}
public class OrderStatus
{
public int OrderStatusId;
public string Status;
}
You always need navigation property on at least one side to build a relation. If you don't have navigation properties you have nothing to bind your your foreign key with and it will remain as common column.
Create your model like this instead
public class Customer
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string StreetAddress { get; set; }
//etc...
//navigation properties
public virtual List<Order> Orders { get; set; }
}
public class Order
{
public int Id { get; set; }
public string OrderStatus { get; set; }
//navigation properties
public virtual Customer OrderedBy { get; set; }
//etc..
}
EF will create your foreign keys on its own using you navigation properties
no reason to expose them to the model as it is unnecessary you can access the id if necessary using the navigation properties