EF Core Creates 2 Columns For Navigation - ef-code-first

I'm trying to link two tables together but EF Core creates two seperate columns for the same navigation property.
This is the ShoppingCart model. It should have the default ApplicationUsers GUID value as foreign key.
public class ShoppingCart : BaseEntity
{
public Guid BasketGuid { get; set; }
public Guid ApplicationUserId { get; set; }
public virtual ApplicationUser ApplicationUser { get; set; }
public virtual ICollection<ShoppingCartItem> ShoppingCartItems { get; set; }
}
But it creates the table like the picture below.
How can I change the model so I can insure that only one navigation property is created correctly?

Related

.NET EF Inheritance without keys or constraints

It is possible to inherit from a type in dotnet EF without inherit the keys, indexes, etc?
I have these types:
public class Product : IEntity<long>
{
public long Id { get; set; }
public string Name { get; set; }
}
public class ProductVersion : Product
{
[Key]
public int ProductVersionId { get; set; }
public DateTime CreatedAt { get; set; }
}
I want ProductVersion to inherit all the properties from Product without creating any keys, constraints or navigation properties from the parent, just have the same properties and if are required or not, basically create a copy of the table columns.
The way you have it set up should remove the key constraint:
https://www.tektutorialshub.com/entity-framework-core/data-annotations-key-attribute-in-ef-core/
Adding [NotInherritedAttribute] should get rid of any of restraints you add:
https://learn.microsoft.com/en-us/dotnet/api/system.attributeusageattribute.inherited?view=net-6.0
[NotInheritedAttribute]
public class ProductVersion : Product{
[Key]
public int ProductVersionId { get; set; }
public DateTime CreatedAt { get; set; }
}

Cannot migrate AspNetUser entity in Entity Framework Code First Approach in .NET

I am developing an ASP.NET MVC project using Visual Studio 2013. I am using Entity Framework Code First Approach to interact with database. But I am having a problem with migrating data because of built-in identity system in ASP.NET. Everything was fine before I touch to identity system.
These are the steps I have done.
I registered an account from UI using built-in identity system. So AspNetUsers table is created in database.
I created AspNetUser class to my code because I need to work with it.
Then I run migration and update database command. It throws error.
This is my AspNetUser class
public class AspNetUser
{
[Required]
public String Id { get; set; }
[Required]
public String UserName { get; set; }
public String PasswordHash { get; set; }
public String SecurityStamp { get; set; }
[Required]
public String Discriminator { get; set; }
}
This is my db context class
public class AyarDbContext : DbContext
{
public AyarDbContext()
: base("DefaultConnection")
{
}
public DbSet<Category> Categories { get; set; }
public DbSet<Region> Regions { get; set; }
public DbSet<Area> Areas { get; set; }
public DbSet<Item> Items { get; set; }
public DbSet<ItemContactInfo> ItemContacts { get; set; }
public DbSet<Gallery> Galleries { get; set; }
public DbSet<Mail> Mails { get; set; }
public DbSet<AspNetUser> AspNetUsers { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
}
}
This is the error I got.
There is already an object named 'AspNetUsers' in the database.
How can I migrate AspNetUser class? I registered using UI because I auto create the other tables need for identity system. How can I migrate that class and map with AspNetUsers table that is already existing in database.
As the error explains, that table already exists and is accessible in this way:
var user = context.Users.First(u => u.Id == myId);
If you want to extend the user class and add properties, you can inherit it:
public class MyAppUser : IdentityUser
{
// don't include properties already in IdentityUser
public string MyNewProperty { get; set; }
}
http://johnatten.com/2014/06/22/asp-net-identity-2-0-customizing-users-and-roles/

EF-Code First navigation property foreign key in complex type

I have complex type for Audit fields
My complex type:
[ComplexType]
public class AuditData {
[Column("CreatorUserId")]
public int? CreatorUserId { get; set; }
public DateTime? CreationTime { get; set; }
[Column("ModifierUserId")]
public int? ModifierUserId { get; set; }
public DateTime? ModificationTime { get; set; }
}
My base Entity (all other inherti this one) has AuditData property:
public abstract class Entity : IEntity, IAuditedEntity, INotifiedDbContextBeforeSave
{
// Summary:
// Unique identifier for this entity.
public int Id { get; set; }
public bool IsActive { get; set; }
public int Old_Id { get; set; }
public string Old_TableName { get; set; }
[Timestamp]
public byte[] RowVersion { get; set; }
public AuditData AuditData { get; set; }
// can this 2 lines below work as navigation property with foreign key in complex type
public virtual User CreatorUser { get; set; }
public virtual User ModifierUser { get; set; }
//... other fields
}
I have 2 navigation properties CreatorUser and ModifierUser.
I know you cant have navigation property in ComplexType but can my navigation property on entity be mapped with foreign key in complexType
something like:
[ForeignKey("CreatorUserId")] // --> should point to AuditData.CreatorUserId
public virtual User CreatorUser { get; set; }
becouse CreatorUserId will be property in every entity but EF is not aware of it.
Mybe there is solution in fluent API ?
The official documentation says:
Complex types are non-scalar properties of entity types that enable scalar properties to be organized within entities. Like entities, complex types consist of scalar properties or other complex type properties. Because complex types do not have keys, complex type objects cannot be managed by the Entity Framework apart from the parent object.
It follows that that complex types can not participate in any relations among entities, so they can't contain foreign keys

Is it OK to declare a DBSet in the context for both a base table and a derived table?

I have a SalesOrder table which inherits from a SalesDocument table using Table Per Type Inheritance
The ( simplified) table classes are;
[Table("SalesDocumentHeaders")]
public abstract class SalesDocumentHeader
{
[ForeignKey("CreatedByUserId")]
public virtual User CreatedBy { get; set; }
[Required]
public int CreatedByUserId { get; set; }
[Required]
public virtual DateTime? DocumentDate { get; set; }
[Required]
public String ReferenceNumber { get; set; }
}
[Table("SalesOrders")]
public class SalesOrder : SalesDocumentHeader
{
[Required]
public String CustomerOrderNumber { get; set; }
public DateTime? DeliverBy { get; set; }
public virtual SortableBindingList<SalesOrderLine> Lines { get; set; }
}
The context contains
public DbSet<SalesOrder> SalesOrders { get; set; }
public DbSet<SalesDocumentHeader> SalesDocumentHeaders { get; set; }
It doesn't strictly need the SalesOrders DBSet, since SalesOrder inherits from SalesDocumentHeader however I find it convenient.
It seems to work OK, but I am worried that there are 2 ways of reaching the same record , am I doing something wrong?
Usually you only need to keep the DBSet for the base table. This helps when you have multiple derived tables (call them A and B) and you need to decide the actual type dynamically.
For example if you have another entity which references type A or B (like a user can have different types of contact information), you can reference the base table and EF will resolve the correct concrete type at runtime. Though of course this adds some extra casting code.

make both models aware of each other with a one-to-one relationship in asp.net entity framework

I am unable to get the one to one relationship with EF to work properly. I've scored blogs, SO, and msdn docs, but nothing I do seems to work.
I have two models, a Class and an Exam that look like the following:
[Table("classes")]
public class Class
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[StringLength(255), Required]
public string Title { get; set; }
public virtual Exam Exam { get; set; }
}
[Table("exams")]
public class Exam
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[DisplayFormat(DataFormatString = "{0:h:mm tt}")]
public DateTime? Time { get; set; }
public int ClassId { get; set; }
public virtual Class Class { get; set; }
}
I want to be able to access the exam from the Class and the Class from the Exam, but no matter what I do, I find some error.
Trying to create/run migrations I get the following.
The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.
If I add this to my context:
protected override void OnModelCreating(DbModelBuilder builder)
{
builder.Entity<Exam>()
.HasRequired(e => e.Class)
.WithOptional(c => c.Exam);
}
I get the following error:
System.Data.Entity.Infrastructure.DbUpdateException: Entities in 'BenchContext.Exams' participate in the 'Class_Exam' relationship. 0 related 'Class_Exam_Source' were found. 1 'Class_Exam_Source' is expected. ---> System.Data.UpdateException: Entities in 'BenchContext.Exams' participate in the 'Class_Exam' relationship. 0 related 'Class_Exam_Source' were found. 1 'Class_Exam_Source' is expected.
I'm not sure how to tell the fluent api how to correctly foreign key between the two models and nothing I do seems to affect it.
What am I missing?
You are trying to build one-to-one relation through ClassId property in Exam class. That requires ClassId to be unique (= unique constraint) but unique constraint are not supported by EF yet.
The only way EF currently supports real one-to-one relation is by sharing primary key:
[Table("classes")]
public class Class
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[StringLength(255), Required]
public string Title { get; set; }
public virtual Exam Exam { get; set; }
}
[Table("exams")]
public class Exam
{
[Key, ForeignKey("Class")]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.None)]
public int Id { get; set; }
[DisplayFormat(DataFormatString = "{0:h:mm tt}")]
public DateTime? Time { get; set; }
public virtual Class Class { get; set; }
}
The Id in Exams table is both PK and FK to Classes table. It cannot have autogenerated value. While this is one-to-one relation it still has 1 - 0..1 multiplicity (Class can exist without Exam but Exam must have Class).

Resources