Let's say I have the following entities:
Box
Id
Crank crank // has one required relationship
Crank
Id // does not care about the box
What is the proper way to define BoxMap? Is this sufficient? Or do I need WithRequiredPrincipal (which I have no idea what that does):
HasKey(t => t.Id);
ToTable("Boxes")
Property(t=>t.Id).HasColumnName("Id")
Property(t=>t.CrankId).HasColumnName("Crank_Id")
HasRequired(t=>t.Crank)
NOTE: Any good resources on learning fluent api are welcome. Thanks.
public class Context : DbContext
{
public DbSet<Box> Boxes { get; set; }
public DbSet<Crank> Cranks { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Box>()
.HasRequired(m => m.Crank)
.WithOptional()
.Map(m => m.MapKey("Crank_Id"));
base.OnModelCreating(modelBuilder);
}
}
public class Box
{
public int Id { get; set; }
public Crank Crank { get; set; } // has one required relationship
}
public class Crank
{
public int Id { get; set; }
}
You don't need to specify this:
HasKey(t => t.Id);
ToTable("Boxes")
Property(t=>t.Id).HasColumnName("Id")
Property(t=>t.CrankId).HasColumnName("Crank_Id")
HasRequired(t=>t.Crank)
It will be detected by convention of EF.
Related
Entity Framework Core DbSet is not returning any data from database, but the database has many register.
This is the entity
public class Entity : BaseEntity
{
public int EntityStatusId { get; set; }
public int AddressId { get; set; }
public string Name { get; set; }
public string SocialReason { get; set; }
public string CNPJ { get; set; }
public EntityType Type { get; set; }
public DateTime? CreationDate { get; set; }
public bool? ReceiptDisabled { get; set; }
public EntityStatus EntityStatus { get; set; }
public Address Address { get; set; }
public List<Company> Companies { get; set; }
public List<Role> RoleList { get; set; }
}
public abstract class BaseEntity
{
public int Id { get; set; }
}
Now this is the configuration class.
public class EntityMap : IEntityTypeConfiguration<Entity>
{
public void Configure(EntityTypeBuilder<Entity> builder)
{
builder.ToTable("Entity");
builder.HasKey(entity => entity.Id);
builder
.Property(entity => entity.EntityStatusId);
builder
.Property(entity => entity.AddressId);
builder
.Property(entity => entity.Name);
builder
.Property(entity => entity.SocialReason);
builder
.Property(entity => entity.CNPJ);
builder
.Property(entity => entity.Type)
.HasConversion(x => (int)x, x => (EntityType)x);
builder
.Property(entity => entity.CreationDate);
builder
.Property(entity => entity.ReceiptDisabled);
builder
.HasOne(entity => entity.EntityStatus);
builder
.HasOne(entity => entity.Address);
builder
.HasMany(entity => entity.RoleList)
.WithOne(x => x.Entity);
builder
.HasMany(entity => entity.Companies)
.WithOne(x => x.Entity);
}
}
And the context class.
public class AucContext : DbContext
{
public AucContext(string databaseConfiguration)
{
_databaseConfiguration = databaseConfiguration;
}
private readonly string _databaseConfiguration;
public DbSet<Campaign> Campaigns { get; set; }
public DbSet<CampaignProject> CampaignProjects { get; set; }
public DbSet<Company> Companies { get; set; }
public DbSet<Cart> Carts { get; set; }
public DbSet<CartItem> CartItems { get; set; }
public DbSet<Donation> Donations { get; set; }
public DbSet<DonationRecurrencePeriod> DonationRecurrencePeriods { get; set; }
public DbSet<Entity> Entities { get; set; }
public DbSet<Institution> Institutions { get; set; }
public DbSet<PaymentMethod> PaymentMethods { get; set; }
public DbSet<Person> People { get; set; }
public DbSet<Project> Projects { get; set; }
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfiguration(new CampaignMap());
modelBuilder.ApplyConfiguration(new CampaignProjectMap());
modelBuilder.ApplyConfiguration(new CompanyMap());
modelBuilder.ApplyConfiguration(new CartMap());
modelBuilder.ApplyConfiguration(new CartItemMap());
modelBuilder.ApplyConfiguration(new DonationMap());
modelBuilder.ApplyConfiguration(new DonationRecurrencePeriodMap());
modelBuilder.ApplyConfiguration(new EntityMap());
modelBuilder.ApplyConfiguration(new InstitutionMap());
modelBuilder.ApplyConfiguration(new PaymentMethodMap());
modelBuilder.ApplyConfiguration(new PersonMap());
modelBuilder.ApplyConfiguration(new ProjectMap());
modelBuilder.ApplyConfiguration(new UserMap());
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(_databaseConfiguration);
}
}
And the query was simple
var entity = context.Entities.Find(3)
this simple query is returning nothing, any ideas for what is happening?
Update
I have updated somethings since yesterday, and now i have updated the question unfortunately still don't work
OBS:. The ConnectionString it's ok, other objects just work fine.
First, add Id to your Entity:
public int Id { get; set; }
Then in your DbContext:
1:In your OnModelCreating,add
modelBuilder.ApplyConfiguration(new EntityMap());
2:Add DbSet:
public DbSet<Entity> Entity { get; set; }
Re-migrate and update the database.Your code will work fine.
An interesting problem if some entities work but this one doesn't. There are a couple additional things to check/try:
Ensure you have no duplicate mappings. For example, if your Entity has a HasMany.WithOne relationship with another entity, ensure that the mapping for that other entity does not declare a HasOne.WithMany or other relationship back to Entity. This can cause weird behaviour.
Your HasOne relationships are missing WithMany and FK declarations. Given you are using "Id" as a base inherited PK on your entities you should consider explicitly declaring your FK relationships. The WithMany declaration is optional in EFCore, however it is needed to declare the FK if it doesn't follow convention. (and I'm no fan of convention for just deciding not to work)
builder
.HasOne(entity => entity.EntityStatus)
.WIthMany()
.HasForeignKey(entity => entity.EntityStatusId);
builder
.HasOne(entity => entity.Address);
.WIthMany()
.HasForeignKey(entity => entity.AddressId);
EF should be working out the FK names by convention though. Just keep in mind that EF conventions follow the type name, not property name so for instance something like this:
public User CreatedBy { get; set; }
by convention would be looking for a FK property of UserId rather than CreatedById which can lead to weird behaviour or errors.
On a side note you do not need to declare .Property() for each property in an entity, only for properties that require some special configuration like IdentityColumn, NotMapped (ignore) or specifying a data constraint / length etc. I would also recommend removing the .Property() statement for any FK columns in your entity
This all said, I've tinkered with a test EF Core project setting up duplicate mapping between objects and leaving off WithMany() and FK declarations and I was not able to reproduce your issue. I think there is something very specific to your schema or mapping that is tripping up EF to resolve this "Entity" object. If these changes do not work, take it down to the minimum viable object and remove all related entity mappings, setting them all to NotMapped so-as not to break your code and then try loading your Entity objects. From there re-introduce the relationships one by one until it stops loading them and narrow it down. If you do identify a rogue mapping responsible, do be sure to post an update with details about the culprit because it would probably be useful in case someone else gets tripped up by it.
I am using ef core 3.0 code-first database. I have a table, Status, and I need to create a relationship to itself to list the possible "next status" List<Status> SubsequentStatuses. This is of course to systematically control the workflow of the object.
Using this at face value, it creates a one-to-many relationship and a new StatusId column in the table; however, I need to be able to set a status to be a "SubsequentStatus" to more than one Status.
For example, if there are 4 statuses:
New
In Work
Complete
Cancelled
I want to have the following
New
Subsequent Statuses
In Work
Cancelled
In Work
Subsequent Statuses
Complete
Cancelled
Complete
None
Cancelled
None
Notice that "Cancelled" is related to both "New" and "In Work"
Here are the classes and config that I have at this point:
public class EstimateStatus
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<EstimateStatusRel> SubsequentStatuses { get; set; }
}
public class EstimateStatusRel
{
public int EstimateStatusId { get; set; }
public EstimateStatus EstimateStatus { get; set; }
public int SubsequentStatusId { get; set; }
public EstimateStatus SubsequentStatus { get; set; }
}
public class SapphireContext : DbContext
{
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<EstimateStatusRel>().HasKey(x => new { x.EstimateStatusId, x.SubsequentStatusId });
modelBuilder.Entity<StatusRel>()
.HasOne(pt => pt.Status)
.WithMany(p => p.SubsequentStatuses)
.HasForeignKey(pt => pt.StatusId);
}
}
The issue this is creating, is that when Entity Framework is building the migration, it errors out about the multiple cascading delete action, but when I add the NoAction modifier to the modelBuilder fluent API, it still does not clear the error
It ended up being because I didn't specify an OnDelete action
This is my final config:
modelBuilder.Entity<EstimateStatusRel>()
.HasOne(pt => pt.Status)
.WithMany(p => p.SubsequentStatus)
.HasForeignKey(pt => pt.EstimateStatusId)
.OnDelete(DeleteBehavior.NoAction);
For self-reference in one-to-many relationships, you could try the below code:
public class EstimateStatus
{
public int Id { get; set; }
public string Name { get; set; }
public int? ParentId { get; set; }
public EstimateStatus ParentStatuses { get; set; }
public virtual ICollection<EstimateStatus> SubsequentStatuses { get; set; }
}
public class TestDbContext:DbContext
{
public TestDbContext (DbContextOptions<TestDbContext> options):base(options)
{ }
public DbSet<EstimateStatus> EstimateStatuse { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<EstimateStatus>()
.HasMany(e => e.SubsequentStatuses)
.WithOne(s => s.ParentStatuses)
.HasForeignKey(e => e.ParentId);
}
}
This question already has answers here:
The entity type 'Microsoft.AspNet.Identity.EntityFramework.IdentityUserLogin<string>' requires a key to be defined
(4 answers)
Closed 4 years ago.
I am using 2 different Dbcontexts. i want to use 2 different databases users and mycontext. While doing that i am getting a error The entity type 'Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin' requires a primary key to be defined. I think there is something wrong with IdentityUser please suggest me where can i change my code so that i can add migration.
My Dbcontext class:
class MyContext : DbContext
{
public DbSet<Post> Posts { get; set; }
public DbSet<Tag> Tags { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<PostTag>()
.HasKey(t => new { t.PostId, t.TagId });
modelBuilder.Entity<PostTag>()
.HasOne(pt => pt.Post)
.WithMany(p => p.PostTags)
.HasForeignKey(pt => pt.PostId);
modelBuilder.Entity<PostTag>()
.HasOne(pt => pt.Tag)
.WithMany(t => t.PostTags)
.HasForeignKey(pt => pt.TagId);
}
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public AppUser User {get; set;}
public string Content { get; set; }
public List<PostTag> PostTags { get; set; }
}
public class Tag
{
public string TagId { get; set; }
public List<PostTag> PostTags { get; set; }
}
public class PostTag
{
public int PostId { get; set; }
public Post Post { get; set; }
public string TagId { get; set; }
public Tag Tag { get; set; }
}
and AppUser class:
public class AppUser : IdentityUser
{
//some other propeties
}
when I try to Add migration the following error occurs.
The entity type 'Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin<string>' requires a primary key to be defined.
give me solution to resolve the issue..
To reduce the link to a nutshell, try this:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
...
See Above link for more.
This issue will start coming as soon as you wrote the following lines in DBContext without adding 'base.OnModelCreating(modelBuilder);'
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
}
Two solutions:
1) Don't override OnModelCreating in DbContext Until it becomes necessary
2) Override but call base.OnModelCreating(modelBuilder)
The problem is AppUser is inherited from IdentityUser and their primary keys are not mapped in the method OnModelCreating of dbcontext.
There is already a post available with resolution. Visit the below link
EntityType 'IdentityUserLogin' has no key defined. Define the key for this EntityType
Hope this helps.
Is there a way to map two entities to have one to one relationship optional on both sides using fluent API in Entity Framework 6?
Code example:
// Subscription (has FK OrderId)
this.HasOptional(t => t.Order)
.WithOptionalDependent(t => t.Subscription)
.HasForeignKey(d => d.OrderId); // does not compile
Context: why would I do this? I work in an existing system where there are payment orders to buy subscriptions. When a order get paid a subscription is created and associated whit it, meaning subscription is optional to order. Also, there are other ways to create subscriptions, meaning order is optional to subscription.
Usually in an one-to-one (or zero) relationship both entities shares the same PK and, in the dependent one, the PK is also specified as FK. Check this link for more info about this. But if you entities not share the same PK, then you can't add a FK property in the dependent entity. If you do that, EF will throw an exception related with the multiplicity saying that it must be *.
About the relationship's configuration, there is only one way to configure an one-to-one relationship with both sides as optional, which it is what you currently have using Fluent Api. This way you can also use the Map method to rename the FK column that EF create by convention in the dependent table by the name that you already have in the Subscription table in your DB.
Update
If you were not tied to an existing database, you could do something like this:
public class Subscription
{
public int SubscriptionId { get; set; }
public int? OrderId { get; set; }
public virtual Order Order { get; set; }
}
public class Order
{
public int OrderId { get; set; }
public int SubscriptionId { get; set; }
public virtual Subscription Subscription { get; set; }
}
And the configuration would be this:
modelBuilder.Entity<Subscription>()
.HasOptional(s => s.Order)
.WithMany()
.HasForeignKey(s=>s.OrderId);
modelBuilder.Entity<>(Order)
.HasOptional(s => s.Subscription)
.WithMany()
.HasForeignKey(s=>s.SubscriptionId);
This way you can work with the OrderIdFK (and SubscriptionId too) like it was a one-to-one relationship. The problem here is you have to set and save both associations separately.
Kindly try this code in the database context class
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Subscription>()
.HasOptional(x => x.Order)
.WithOptionalPrincipal()
.Map(x => x.MapKey("SubscriptionId"));
modelBuilder.Entity<Order>()
.HasOptional(x => x.Subscription)
.WithOptionalPrincipal()
.Map(x => x.MapKey("OrderId"));
}
My test models are as follows
public class Order
{
[Key]
public int OrderId { get; set; }
public string Description { get; set; }
public virtual Subscription Subscription { get; set; }
}
public class Subscription
{
[Key]
public int SubscriptionId { get; set; }
public virtual Order Order { get; set; }
}
Edit:
I did a reverse engineering to database trying to reach the required code structure by using double 1 to many relation to work like you want. The generated code is like the following. However, It is bad idea to do so.
public partial class Order
{
public Order()
{
this.Subscriptions = new List<Subscription>();
}
public int OrderId { get; set; }
public string Description { get; set; }
public Nullable<int> SubscriptionId { get; set; }
public virtual Subscription Subscription { get; set; }
public virtual ICollection<Subscription> Subscriptions { get; set; }
}
public partial class Subscription
{
public Subscription()
{
this.Orders = new List<Order>();
}
public int SubscriptionId { get; set; }
public Nullable<int> OrderId { get; set; }
public virtual ICollection<Order> Orders { get; set; }
public virtual Order Order { get; set; }
}
public class OrderMap : EntityTypeConfiguration<Order>
{
public OrderMap()
{
// Primary Key
this.HasKey(t => t.OrderId);
// Properties
// Table & Column Mappings
this.ToTable("Orders");
this.Property(t => t.OrderId).HasColumnName("OrderId");
this.Property(t => t.Description).HasColumnName("Description");
this.Property(t => t.SubscriptionId).HasColumnName("SubscriptionId");
// Relationships
this.HasOptional(t => t.Subscription)
.WithMany(t => t.Orders)
.HasForeignKey(d => d.SubscriptionId);
}
}
public class SubscriptionMap : EntityTypeConfiguration<Subscription>
{
public SubscriptionMap()
{
// Primary Key
this.HasKey(t => t.SubscriptionId);
// Properties
// Table & Column Mappings
this.ToTable("Subscriptions");
this.Property(t => t.SubscriptionId).HasColumnName("SubscriptionId");
this.Property(t => t.OrderId).HasColumnName("OrderId");
// Relationships
this.HasOptional(t => t.Order)
.WithMany(t => t.Subscriptions)
.HasForeignKey(d => d.OrderId);
}
}
public partial class EFOrdersContextContext : DbContext
{
static EFOrdersContextContext()
{
Database.SetInitializer<EFOrdersContextContext>(null);
}
public EFOrdersContextContext()
: base("Name=EFOrdersContextContext")
{
}
public DbSet<Order> Orders { get; set; }
public DbSet<Subscription> Subscriptions { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new OrderMap());
modelBuilder.Configurations.Add(new SubscriptionMap());
}
}
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.