Entity Framework Core fails to recognize Key Attribute - c#

I am using .Net Core 3. Brand new project, with Identity.
I've made a simple new entity to add to the database. I get the following error on startup. As you can see, I have already added the [Key] attribute to the entity and it will still not register.
public class DataContext : IdentityDbContext
{
public DataContext(DbContextOptions<DataContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
}
public DbSet<LocationRecord> LocationRecords { get; set; }
public DbSet<LocationActivity> LocationActivities { get; set; }
}
And the model class:
public class LocationActivity
{
[Key]
public Guid Id;
public DateTime Moment { get; set; }
public double Latitude { get; set; }
public double Longitude { get; set; }
public int Confidence { get; set; }
public string ActivityType { get; set; }
public string UserId { get; set; }
[ForeignKey(nameof(UserId))]
public IdentityUser User { get; set; }
}

Your Id is a field rather than a property. Try rewriting like so:
public class LocationActivity {
[Key]
public Guid Id {get; set;}
.......

Related

EF Core Fluent API For Base Class Setting FK

I am trying to set up audit properties for each of my Entities with an abstract Base class
public abstract class Base
{
public bool IsActive { get; set; }
public bool IsDeleted { get; set; }
public int CreatedByUserId { get; set; }
[ForeignKey("CreatedByUserId")]
public virtual User CreatedBy { get; set; }
public int ModifiedByUserId { get; set; }
[ForeignKey("ModifiedByUserId")]
public virtual User ModifiedBy { get; set; }
public DateTime DateCreated { get; set; }
public DateTime DateModified { get; set; }
}
Somehow the Data Annotations doesn't work in EF Core but was working in my EF 6 Project
I am now receiving this error:
Unable to determine the relationship represented by navigation 'Address.CreatedBy' of type 'User'. Either manually configure the relationship, or ignore this property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.
These are my models:
public class Address : Base
{
public int Id { get; set; }
public string StringAddress { get; set; }
public string City { get; set; }
public string State { get; set; }
public string ZipCode { get; set; }
public int UserId { get; set; }
public User User { get; set; }
}
public class User : Base
{
public int Id { get; set; }
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public DateTime BirthDate { get; set; }
public string Email { get; set; }
public string ContactNumber { get; set; }
public string SecondaryContactNumber { get; set; }
public int RoleId { get; set; }
public Role Role { get; set; }
public HashSet<Address> Addresses { get; set; }
}
What's weird is when I remove the Base inheritance from my other entities apart from User, EF Core is able to set the FK without any errors.
How do I configure it manually with Fluent API?
I already have a BaseConfig class as starting point to be inherited by my other entity config classes:
public class BaseConfig<TEntity> : IEntityTypeConfiguration<TEntity> where TEntity : Base
{
public virtual void Configure(EntityTypeBuilder<TEntity> builder)
{
builder.Property(x => x.DateCreated).HasDefaultValueSql("GETDATE()");
builder.Property(x => x.DateModified).HasDefaultValueSql("GETDATE()");
// Am I setting this correctly?
builder
.HasOne(b => b.CreatedBy)
.WithMany()
.HasForeignKey(p => p.CreatedByUserId);
}
}

Data property inheritance in EF Core 3.0

I have a problem with the realization of data hierarchy in EF Core 3.0 (I need to use TPH).
Let's look:
public abstract class User
{
public Guid Id { get; set; }
public string Name { get; set; }
public abstract UserProfile **Profile** { get; set; }
}
public class ConcreteUser1 : User
{
public string ConcreteUser1Prop { get; set; }
public override UserProfile Profile { get; set; }
}
public class ConcreteUser2 : User
{
public string ConcreteUser2Prop { get; set; }
public override UserProfile Profile { get; set; }
}
And here we have Profile classes:
public class UserProfile
{
public Guid Id { get; set; }
public string SameProp { get; set; }
public Guid UserId { get; set; }
public User User { get; set; }
}
public class ConcreteUser1Profile : Profile
{
public string ConcreteProfile1Prop { get; set; }
}
public class ConcreteUser2Profile : Profile
{
public string ConcreteProfile2Prop { get; set; }
}
Let it be only one DbSet<User> which can be used for getting data from Database.
So, I can't understand, how to say EF Core (3.0) 2 things: how to say to store ConcreteUser*Profile (possible, Add and SaveChanges will work properly and write concrete profile type when I add concrete type user with concrete profile type. But I don't know how to say EF Core to get the correct concrete profile type when I use Where or FirstOrDefault method?
Is this model correct in principle?
Upd.
For example, I have 2 records in my Db: ConcreteUser1 user1, ConcreteUser2 user2. So, let's have DbSet<User> Users, so, what will I have after the request: var tstUser = ExampleDbContext.Users.FirstOrDefault();? What will the type of Profile variable in tstUser.Profile?
You can use HasDiscriminator on model creating.
It will use a field to be able to decide which concrete user class you're trying map the data to.
For you it'll be something like:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.HasDiscriminator<int>("UserType")
.HasValue<ConcreteUser1>(1)
.HasValue<ConcreteUser2>(2);
}
More at:
https://www.learnentityframeworkcore.com/configuration/fluent-api/hasdiscriminator-method
I have a solution (maybe someone will use it too).
public class UserProfile
{
public Guid Id { get; set; }
public ProfileRoles Role { get; set;}
public string SameProp { get; set; }
public Guid UserId { get; set; }
public User User { get; set; }
}
public class ConcreteUser1Profile : UserProfile
{
public string ConcreteProfile1Prop { get; set; }
}
public class ConcreteUser2Profile : UserProfile
{
public string ConcreteProfile2Prop { get; set; }
}
and
public class User
{
public Guid Id { get; set; }
public string Name { get; set; }
public UserRoles Role { get; set; }
public UserProfile Profile { get; set; }
}
public class ConcreteUser1 : User
{
public string ConcreteUser1Prop { get; set; }
}
public class ConcreteUser2 : User
{
public string ConcreteUser2Prop { get; set; }
}
public enum UserRoles
{
User = 0,
ConcreteUser1 = 1,
ConcreteUser2 = 2
}
public enum ProfileRoles
{
BaseProfile = 0,
ConcreteProfile1 = 1,
ConcreteProfile2 = 2
}
And It needs to be configured well in the DbContext:
public class UserStoreDbContext : DbContext
{
DbSet<User> Users { get; set; }
DbSet<UserProfile> Profiles { get; set; }
public UserStoreDbContext(DbContextOptions<UserStoreDbContext> options) : base(options) { }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<User>(builder =>
{
builder.HasDiscriminator<UserRoles>(x => x.Role)
.HasValue<User>(Roles.User)
.HasValue<Logistian>(Roles.ConcreteUser1)
.HasValue<Driver>(Roles.ConcreteUser2)
});
modelBuilder.Entity<UserProfile>(builder =>
{
builder.HasDiscriminator<ProfileRoles>(x => x.Role)
.HasValue<UserProfile>(ProfileRoles.BaseProfile)
.HasValue<ConcreteUser1Profile>(Roles.ConcreteProfile1)
.HasValue<ConcreteUser2Profile>(Roles.ConcreteProfile2)
});
}
}
In this case when you will use the code like: dbContext.Users.FirstOrDefault(), you also will get correct derived profile from UserProfile.
Maybe someone will need this solution too.

EF Core - Single Selection of child collection stored at parent

Working with .NET Core 3.0 and EF Core if that impacts things.
I'm trying to define a model where:
A user owns a collection of toys.
A user can have a currently selected toy.
I'm trying to model this as such (BaseModel has common properties to all my entities), and AVUser is my ASP.NET Identity user class.
public abstract class BaseModel
{
public int Id { get; set; }
public DateTime LastModifiedDate { get; set; }
public DateTime CreatedDate { get; set; }
public AVUser CreatedUser { get; set; }
public AVUser ModifiedUser { get; set; }
}
public class Toy: BaseModel
{
[MaxLength(80)]
public string Name { get; set; }
}
public class AVUser : IdentityUser
{
public string FirstName { get; set; }
// The currently selected toy for the user.
public int SelectedToyId { get; set; }
public Toy SelectedToy { get; set; }
}
However, EF Core throws an error stating: Unable to determine the relationship represented by navigation property 'AVUser.Toy' of type 'Toy'.
I am having trouble how I annotate this so it knows that the user can have a collection of toys, and I want to store a single toy with the user as the currently selected one.
Write your model classes as follows:
public class Toy: BaseModel
{
[MaxLength(80)]
public string Name { get; set; }
[ForeignKey("AVUser")]
public string UserId { get; set; }
public AVUser AVUser { get; set; }
}
public class AVUser : IdentityUser
{
public string FirstName { get; set; }
// The currently selected toy for the user.
[ForeignKey("SelectedToy")]
public int SelectedToyId { get; set; }
public Toy SelectedToy { get; set; }
public ICollection<Toy> Toys {get; set;}
}
Then configure in the OnModelCreating in DbContext as follows:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<AVUser>().HasOne(a => a.SelectedToy).WithOne();
modelBuilder.Entity<AVUser>().HasMany(a => a.Toys).WithOne(t => t.AVUser).HasForeignKey(t => t.UserId);
}

"Column names in each table must be unique." during database update

I am quite new to ASP.NET at all, however this is my first app with ASP.NET Core. I have problem with updating database after creating the migration. While I type command: dotnet ef database update, I get error:
Column names in each table must be unique. Column name 'PortalUserId'
in table 'Adverts' is specified more than once.
I think the problem is with my model structure, but I do not know what I am doing wrong. When I was developing with ASP.NET MVC 5 everything was Ok.
Here is my Model (without unnecessary for the case entities):
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<PortalUser> PortalUsers { get; set; }
public DbSet<Advert> Adverts { get; set; }
public DbSet<Category> Categories { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
// Customize the ASP.NET Identity model and override the defaults if needed.
// For example, you can rename the ASP.NET Identity table names and more.
// Add your customizations after calling base.OnModelCreating(builder);
}
}
public class Advert
{
public int ID { get; set; }
public string Title { get; set; }
public int CategoryID { get; set; }
public virtual Category Category { get; set; }
public int PortalUserID { get; set; }
public PortalUser PortalUser { get; set; }
}
public class PortalUser : IdentityUser
{
public string FirstName { get; set; }
public string Surname { get; set; }
public ICollection<Advert> Adverts { get; set; }
}
What I am doing here is normal virtual mapping for lazy loading purposes. I am storing FK to PortalUser in Advert field.
I will appreciate every helpful answer!
I already figure out, that lazy loading is not supported so now my model looks like in the official tutorial:
https://learn.microsoft.com/en-us/ef/core/get-started/aspnetcore/new-db
public class BloggingContext : DbContext
{
public BloggingContext(DbContextOptions<BloggingContext> options)
: base(options)
{ }
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public List<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
public Blog Blog { get; set; }
}
Okay, guys, I found the solution! All what is needed, it is change type of property PortalUserId from int to string. Than everythings compiles and no doubled field appears!
Thanks for at least trying to help me!

Table per hierarchy not default behavior of EF6

I'm trying to map these three classes to one EF table. In this scenario, my base class actually has a base Entity class, is this causing my issue? I'm not finding any examples that cover a scenario where the default behavior isn't handled properly.
Base Class:
public abstract class Connection : Entity
{
public override int Id { get; set; }
public ContactEnums.ConnectionType Type { get; set; }
public string Value { get; set; }
}
Child Classes:
public class BusinessConnection : Connection
{
[ForeignKey("Business")]
public int BusinessId { get; set; }
public Business Business { get; set; }
}
public class ContactConnection : Connection
{
[ForeignKey("Contact")]
public int ContactId { get; set; }
public Contact Contact { get; set; }
}
Entity Base class:
public abstract class Entity : EqualityAndHashCodeProvider<Entity, int>
{
public override int Id { get; set; }
public string CreatedBy { get; set; }
public DateTime CreatedDate { get; set; }
public string UpdatedBy { get; set; }
public DateTime UpdatedDate { get; set; }
[NotMapped]
public ObjectState ObjectState { get; set; }
}

Categories