How to define relationships on ef core 3? - entity-framework

im a beginner on the .net core and ef stuff and i would like to get some help about a little project that im doing (.Net Core WebApi)
To clarify what im doing here is the diagram:
And here is the code that i wrote as model classes:
Is all that code correct representing what i tried to do? Do i have to declare props like the id first and then the prop of the other class type with the [ForeignKey] Annotation?
Also for example, if i want to do a post request with a character information, should i send the json like this?:
{
"Name":"Lost Vayne Meliodas",
"Awaken":6,
"Level":80,
"AttributeId":1,
"RarityId":4
}
Thanks!

You should be using FluentAPI.
In your dbcontext class, you should be having 3 dbsets as follows
public DbSet<Character> Character { get; set; }
public DbSet<Rarity> Rarity { get; set; }
public DbSet<Attribute> Attribute { get; set; }
//You need to have a OnModelCreating method in the same dbcontext class
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Rarity>()
.HasMany(c => c.Characters)
.WithOne(e => e.Rarity);
modelBuilder.Entity<Attribute>()
.HasMany(c => c.Characters)
.WithOne(e => e.Attribute);
}
Add this to your Rarity table
public ICollection<Character> Characters { get; set; }
Add this to your Attribute table
public ICollection<Character> Characters { get; set; }

Related

How can I define a 1:0 relationship using Entity Framework Core 2.1? [duplicate]

This question already has an answer here:
One-to-Zero relationship with Entity Framework Core 2.0
(1 answer)
Closed 4 years ago.
Updating entity Persons I get the following error:
System.InvalidOperationException: The property 'ID' on entity type 'Person' has a temporary value. Either set a permanent value explicitly or ensure that the database is configured to generate values for this property.
at Microsoft.EntityFrameworkCore....
This has been discussed several places, and a similar issue was reported fixed by the EF Core team. However, one of those posts is about multiple updates to an entity and the one-to-many solution does not work here; additionally, I cannot make one ID column nullable and prefer to use the fluent API configuration. The documentation example does not work either, so I am asking here.
The scenario is that I am upgrading a legacy ASP.NET MVC 4 project to ASP.NET MVC Core, and as a result I am upgrading from EF 6.1 to EF Core 2.1. I will happily move to 2.2 instead if it solves this problem; I think it was still in prerelease when I started.
Here is a (ridiculously) simplified version of my entities:
public class Person
{
public int ID { get; set; }
public string name { get; set; }
public virtual Worker Worker { get; set; }
}
public class Worker
{
public int ID { get; set; }
public string somePersonalDetails { get; set; }
public virtual Person Person { get; set; }
// other relationships exist
}
I am using fluent API configuration:
public class PersonBuilder
{
public PersonBuilder(EntityTypeBuilder<Person> entity)
{
entity.HasKey(k => k.ID);
entity.HasOne(p => p.Worker)
.WithOne(p => p.Person)
.HasForeignKey<Person>(p => p.ID)
//.IsRequired(false) //?
.OnDelete(DeleteBehavior.Cascade);
}
}
public class WorkerBuilder
{
public WorkerBuilder(EntityTypeBuilder<Worker> entity)
{
entity.HasKey(k => k.ID);
// other relationships are defined
}
}
public override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Configurations<Person>().Add(typeof(PersonBuilder));
builder.Configurations<Worker>().Add(typeof(WorkerBuilder));
}
The reason that it's split apart like that is because I adapted it from our leftover EF 4/5/6 configuration. Yay legacy code. Nevertheless it works (for other defined types). The way I am reading that, it says "define a foreign key on the related Worker object pointing to the ID of this object." It does just the opposite.
I have tried:
Defining the key relationship on the WorkerBuilder type instead. This yields SQLite Error 19: 'FOREIGN KEY constraint failed'. Amazingly, however, it still attempts to define the key on the Person entity, which is wrong.
Removing some of the specific expressions in hopes that EF will just figure out the relationship itself. It doesn't; if I provide too little information, it tries to use columns|fields that don't exist (e.g., "PersonID", or is unable to figure out the relationship altogether.
So, I am stumped. Has anyone done this successfully? In plain English,
"A person may or may not have a worker record" (1:0); and,
"if they have a worker record, both records have the same ID." (FK_W_ID__P_ID)
Write your model classes as follows:
public class Person
{
public int PersonId { get; set; }
public string Name { get; set; }
public virtual Worker Worker { get; set; }
}
public class Worker
{
public int PersonId { get; set; }
public string somePersonalDetails { get; set; }
public virtual Person Person { get; set; }
// other relationships exist
}
Then in the PersonConfiguration and WorkerConfiguration:
public class PersonConfiguration : IEntityTypeConfiguration<Person>
{
public void Configure(EntityTypeBuilder<Person> builder)
{
builder.HasKey(u => u.PersonId);
}
}
public class WorkerConfiguration : IEntityTypeConfiguration<Worker>
{
public void Configure(EntityTypeBuilder<Worker> builder)
{
builder.HasKey(u => u.PersonId);
builder.HasOne(u => u.Person)
.WithOne(b => b.Worker)
.HasForeignKey<Worker>(b => b.PersonId);
}
}
Then in the OnModelCreating of DbContext:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyConfiguration(new PersonConfiguration());
modelBuilder.ApplyConfiguration(new WorkerConfiguration());
}

Map Existing Entity with Existing Table in Entity FrameWork

Is it possible to map existing tables with existing Entities in Entity frame work as like NHibernate doing.
For example. I have entity as
public class User
{
public Int64 userId { set; get; }
public String Username { set; get; }
public Int64 RoleId { set; get; }
}
public class Role
{
public Int64 roleId { set; get; }
public String roleName { set; get; }
public IList<User> listUser { set; get; }
}
I have Table as
Users with id,name,roleId
Roles with id,name.
Now I want to map both using XML files. Is it possible to map exiting tables with exiting Entities.
You have a few options:
1) Manage your mapping via the database first edmx file (see http://www.asp.net/mvc/tutorials/mvc-5/database-first-development/creating-the-web-application)
2) Start with the database first approach then move over to a code first like approach using the fluent api (see http://agilenet.wordpress.com/2011/04/11/entity-framework-4-1-rc-with-an-existing-database/)
Usual way of mapping in EF is data annotation attributes or fluent mapping (actually with NHibernate fluent mapping is also better, because it gives you compile-time checks). So, here is fluent mapping for your classes:
public class UserMapping : EntityTypeConfiguration<User>
{
public UserMapping()
{
ToTable("Users"); // Not necessary, EF will use this mapping by default
HasKey(u => u.userId);
Property(u => u.userId).HasColumnName("id");
Property(u => u.Username).HasColumnName("name");
Property(u => u.RoleId).HasColumnName("roleId");
}
}
public class RoleMapping : EntityTypeConfiguration<Role>
{
public RoleMapping()
{
ToTable("Roles"); // Not necessary, EF will use this mapping by default
HasKey(r => r.roleId);
Property(r => r.roleId).HasColumnName("id");
Property(r => r.roleName).HasColumnName("name");
HasMany(r => r.listUser)
.WithRequired()
.HasForeignKey(u => u.RoleId);
}
}
Just provide these mappings to your DbContext:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new UserMapping());
modelBuilder.Configurations.Add(new RoleMapping());
base.OnModelCreating(modelBuilder);
}
I suggest you to read MSDN article Configuring/Mapping Properties and Types with the Fluent API.
Side note - another article to read is Naming Guidelines, especially its Capitalization Styles part.

Entity Framework Code First - Navigation property on Composite Primaty Key

Firebird 2.5
Entity Framework 5
FirebirdClientDll 3.0.0.0
Hi, I'm trying to access my legacy database with the Entity Framework (Code First).
I got the problem that the database does not use foreign keys...
public class CUSTOMERS
{
public int CUSTOMERID { get; set; }
public string NAME{ get; set; }
}
public class INVOICES
{
public int INVOICEID{ get; set; }
public int CUSTOMERID{ get; set; }
public virtual CUSTOMERS CUSTOMERS { get; set; }
}
public class INVOICEContext : DbContext
{
public DbSet<CUSTOMERS> CUSTOMERS{ get; set; }
public DbSet<INVOICES> INVOICES{ get; set; }
public INVOICEContext(DbConnection connectionString) : base(connectionString, false)
{
Database.SetInitializer<INVOICEContext>(null);
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
/*modelBuilder.Entity<INVOICES>().HasRequired(b => b.CUSTOMERS)
.WithMany()
.Map(p => p.MapKey("INVOICEID"));*/ //Doesn't work because INVOICEID is defined
modelBuilder.Entity<INVOICES>().HasKey(a => new { a.INVOICEID, a.CUSTOMERID});
modelBuilder.Entity<CUSTOMERS>().HasKey(a => new { a.CUSTOMERID });
base.OnModelCreating(modelBuilder);
}
}
Normally I could remove the property CUSTOMERID from the class INVOICES, but in this case it is part of the primary key...
I found many threads which suggested to use IsIndependent, but it seems to be removed from the Entity Framework 5 (or 4.1).
I hope you can understand my poor English and maybe give me a hint what I'm doing wrong ^^
I don't know what you mean with "the database does not use foreign keys". So, maybe the following is not the answer you are looking for. But I'd say that you can use your relationship mapping that is commented out in your code if you replace ...MapKey... by HasForeignKey and use CUSTOMERID instead of INVOICEID as the foreign key property:
modelBuilder.Entity<INVOICES>()
.HasRequired(b => b.CUSTOMERS)
.WithMany()
.HasForeignKey(b => b.CUSTOMERID);
The model and the rest of the mapping is fine in my opinion. Your relationship is an identifying relationship (that means that the foreign key is part of a composite primary key) which is a valid mapping with Entity Framework.
Try this ...
modelBuilder.Entity<INVOICES>()
.HasRequired(i => i.CUSTOMERS)
.WithMany()
.HasForeignKey(i => i.CUSTOMERID);

EF 4.1 Code First ModelBuilder HasForeignKey for One to One Relationships

Very simply I am using Entity Framework 4.1 code first and I would like to replace my [ForeignKey(..)] attributes with fluent calls on modelBuilder instead. Something similar to WithRequired(..) and HasForeignKey(..) below which tie an explicit foreign key property (CreatedBySessionId) together with the associated navigation property (CreatedBySession). But I would like to do this for a one to one relationsip instead of a one to many:
modelBuilder.Entity<..>().HasMany(..).WithRequired(x => x.CreatedBySession).HasForeignKey(x => x.CreatedBySessionId)
A more concrete example is below. This works quite happily with the [ForeignKey(..)] attribute but I'd like to do away with it and configure it purely on modelbuilder.
public class VendorApplication
{
public int VendorApplicationId { get; set; }
public int CreatedBySessionId { get; set; }
public virtual Session CreatedBySession { get; set; }
}
public class Session
{
public int SessionId { get; set; }
[ForeignKey("CurrentApplication")]
public int? CurrentApplicationId { get; set; }
public virtual VendorApplication CurrentApplication { get; set; }
public virtual ICollection<VendorApplication> Applications { get; set; }
}
public class MyDataContext: DbContext
{
public IDbSet<VendorApplication> Applications { get; set; }
public IDbSet<Session> Sessions { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Session>().HasMany(x => x.Applications).WithRequired(x => x.CreatedBySession).HasForeignKey(x => x.CreatedBySessionId).WillCascadeOnDelete(false);
// Note: We have to turn off Cascade delete on Session <-> VendorApplication relationship so that SQL doesn't complain about cyclic cascading deletes
}
}
Here a Session can be responsible for creating many VendorApplications (Session.Applications), but a Session is working on at most one VendorApplication at a time (Session.CurrentApplication). I would like to tie the CurrentApplicationId property with the CurrentApplication navigation property in modelBuilder instead of via the [ForeignKey(..)] attribute.
Things I've Tried
When you remove the [ForeignKey(..)] attribute the CurrentApplication property generates a CurrentApplication_VendorApplicationId column in the database which is not tied to the CurrentApplicationId column.
I've tried explicitly mapping the relationship using the CurrentApplicationId column name as below, but obviously this generates an error because the database column name "CurrentApplicationId" is already being used by the property Session.CurrentApplicationId:
modelBuilder.Entity<Session>().HasOptional(x => x.CurrentApplication).WithOptionalDependent().Map(config => config.MapKey("CurrentApplicationId"));
It feels like I'm missing something very obvious here since all I want to do is perform the same operation that [ForeignKey(..)] does but within the model builder. Or is it a case that this is bad practise and was explicitly left out?
You need to map the relationship as one-to-many and omit the collection property in the relationship.
modelBuilder.Entity<Session>()
.HasOptional(x => x.CurrentApplication)
.WithMany()
.HasForeignKey(x => x.CurrentApplicationId)

Specifying Foreign Key Entity Framework Code First, Fluent Api

I have a question about defining Foreign Key in EF Code First Fluent API.
I have a scenario like this:
Two class Person and Car. In my scenario Car can have assign Person or not (one or zero relationship).
Code:
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class Car
{
public int Id { get; set; }
public string Name { get; set; }
public Person Person { get; set; }
public int? PPPPP { get; set; }
}
class TestContext : DbContext
{
public DbSet<Person> Persons { get; set; }
public DbSet<Car> Cars { get; set; }
public TestContext(string connectionString) : base(connectionString)
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Car>()
.HasOptional(x => x.Person)
.WithMany()
.HasForeignKey(x => x.PPPPP)
.WillCascadeOnDelete(true);
base.OnModelCreating(modelBuilder);
}
}
In my sample I want to rename foreign key PersonId to PPPPP. In my mapping I say:
modelBuilder.Entity<Car>()
.HasOptional(x => x.Person)
.WithMany()
.HasForeignKey(x => x.PPPPP)
.WillCascadeOnDelete(true);
But my relationship is one to zero and I'm afraid I do mistake using WithMany method, but EF generate database with proper mappings, and everything works well.
Please say if I'm wrong in my Fluent API code or it's good way to do like now is done.
Thanks for help.
I do not see a problem with the use of fluent API here. If you do not want the collection navigational property(ie: Cars) on the Person class you can use the argument less WithMany method.