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

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!

Related

Retrieve Entity Framework Foreign Key Relationship Models automatically

I am working on a Restaurant Application. I have a restaurant model and a table model.
namespace Restaurant.Models
{
[Table("Restaurant")]
public class RestaurantModel
{
[Key]
[Column("id")]
public int Id { get; set; }
[Column("name")]
public string Name { get; set; }
[Column("telephone_number")]
public int TelephoneNumber { get; set; }
[NotMapped]
public List<TableModel> Tables;
public RestaurantModel()
{
Tables = new List<TableModel>();
}
}
}
namespace Restaurant.Models
{
[Table("Table")]
public class TableModel
{
[Key]
[Column("id")]
public int Id { get; set; }
[ForeignKey("restaurant_id")]
[Required] [NotNull]
public int RestaurantId { get; set; }
[Column("available_seats")]
public int AvailableSeats { get; set; }
[Column("is_indoors")]
public bool IsIndoors { get; set; }
}
}
I have a dependency between Restaurant and Table:
Here are the columns and keys that Entity Framework has created for me via my context:
Lastly, here's my Context class:
namespace Restaurant.Data
{
public class RestaurantContext : DbContext
{
public RestaurantContext(DbContextOptions<RestaurantContext> options) : base(options)
{
}
public DbSet<RestaurantModel> Restaurants { get; set; }
public DbSet<TableModel> Tables { get; set; }
public DbSet<GuestModel> Guests { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<RestaurantModel>().ToTable("Restaurant");
modelBuilder.Entity<TableModel>().ToTable("Table");
modelBuilder.Entity<GuestModel>().ToTable("Guest");
modelBuilder.Entity<TableModel>()
.HasOne<RestaurantModel>();
}
}
}
When I retrieve a restaurant, I want the corresponding tables to be retrieved inside of the TableModel List. Currently, when I retrieve a Restaurant, it will not retrieve any corresponding Tables. This makes sense to me, as I have not properly connected the relationship for EntityFramework to recognize it. I have tried to look online how to do it, consulting guides on setting up Foreign Key relationships and such. I cannot find the information I am looking for, due to a lack of basic knowledge. The answers I can find do not make sense to me because I do not understand what they are doing or how they are doing it.
Could anyone point me in the right direction or tell me what I am doing wrong?
add relations to your classes
[Table("Restaurant")]
public class Restaurant
{
[Key]
[Column("id")]
public int Id { get; set; }
[Column("name")]
public string Name { get; set; }
[Column("telephone_number")]
public int TelephoneNumber { get; set; }
public virtual ICollection<Table> Tables { get; set; }
}
}
[Table("Table")]
public class Table
{
[Key]
[Column("id")]
public int Id { get; set; }
public int? RestaurantId { get; set; }
public virtual Restourant Restaurant { get; set; }
[Column("available_seats")]
public int AvailableSeats { get; set; }
[Column("is_indoors")]
public bool IsIndoors { get; set; }
}
}
and since you are using Net core 5+ I don' t think that you any navigation attributes or fluent APIs
Delete old migration folde and make a clean migration to db
after this you can try this code for test
var restourant= context.Restourants.Include(r=> r.Tables).FirstOrDefault(r=>r.Id==id);
it should return a restourant with a list of tables

Accessing to a table by the string name LINQ

I would like to access to a database table from an string identifier belonging to an equipement. I need to do it like this way because according to the equipement selected I will have an string with the table name with data to request. I test the access to my database and everything is ok.
How to resolve this issue please? Thanks in advance
Request:
var query = (from donnees in "String Name of my table"
where donnees.Chrono >= dateDebut.Ticks
select donnees).Any();
My database class:
public partial class PcVueContext : DbContext
{
public PcVueContext()
{
}
public PcVueContext(DbContextOptions<PcVueContext> options)
: base(options)
{
}
public virtual DbSet<AICommonParameters> AICommonParameters { get; set; }
public virtual DbSet<tab_LOG_TRACA> tab_LOG_TRACA { get; set; }
public virtual DbSet<tab_UA_ACT> tab_UA_ACT { get; set; }
public virtual DbSet<tab_UA_CUV> tab_UA_CUV { get; set; }
public virtual DbSet<tab_UA_ECR> tab_UA_ECR { get; set; }
public virtual DbSet<tab_UA_ENG> tab_UA_ENG { get; set; }
public virtual DbSet<tab_UA_EVAA> tab_UA_EVAA { get; set; }

Entity Framework Core fails to recognize Key Attribute

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;}
.......

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);
}

Categories