Sto scrivendo la mia prima app in MVC Core 2 e sto riscontrando problemi nell'accesso a Estate Entity che ha una chiave esterna per Utente. Ho controllato il mio db, registro immobiliare sta memorizzando userId correttamente:
Quando provo a ottenere context.Estates.FirstOrDefault(m => m.Id == id);
Ricevo un'entità immobiliare, ma con User == null
:
Quando provo ad accedervi tramite:
var user = await _userManager.GetUserAsync(User);
var estate = user.Estates.FirstOrDefault(m => m.Id == id);
Ottengo l'eccezione nulla nella lista delle proprietà. Anche provare a salvarlo in questo modo mi dà un'eccezione:
var user = await _userManager.GetUserAsync(User);
user.Estates.Add(estate);
Tuttavia quando lo digito in questo modo, salva i dati correttamente in db:
var user = await _userManager.GetUserAsync(User);
estate.User = user;
context.Add(estate);
Non ho idea di cosa ho fatto di sbagliato qui. Fornisco il mio codice qui sotto, spero che tu possa darmi alcuni consigli / consigli.
Ecco come costruisco il contesto basato su IdentityDbContext:
public class ReaContext : IdentityDbContext<User>
{
public DbSet<Estate> Estates { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseNpgsql("Server=localhost;Port=5432;Database=rea-dev;User Id=postgres;Password=admin;");
}
public ReaContext(DbContextOptions<ReaContext> options)
: base(options)
{ }
public ReaContext()
: base()
{ }
}
Il mio modello utente:
public class User : IdentityUser
{
public List<Estate> Estates { get; set; }
}
Modello immobiliare:
public class Estate
{
[Key]
public int Id { get; set; }
[MaxLength(100)]
public string City { get; set; }
public User User { get; set; }
}
E questo è il modo in cui aggiungo servizi:
services.AddDbContext<ReaContext>(options => options.UseNpgsql("Server=localhost;Port=5432;Database=rea-dev;User Id=postgres;Password=admin;"));
services.AddIdentity<User, IdentityRole>().AddEntityFrameworkStores<ReaContext>();
Fornisco anche migrazioni di Fluent Api:
migrationBuilder.CreateTable(
name: "Estates",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn),
CreationDate = table.Column<DateTime>(nullable: false),
UpdateDate = table.Column<DateTime>(nullable: false),
ExpirationDate = table.Column<DateTime>(nullable: false),
City = table.Column<string>(maxLength: 100, nullable: true),
UserId = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Estates", x => x.Id);
table.ForeignKey(
name: "FK_Estates_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateTable(
name: "AspNetUsers",
columns: table => new
{
Id = table.Column<string>(nullable: false),
UserName = table.Column<string>(maxLength: 256, nullable: true),
NormalizedUserName = table.Column<string>(maxLength: 256, nullable: true),
Email = table.Column<string>(maxLength: 256, nullable: true),
NormalizedEmail = table.Column<string>(maxLength: 256, nullable: true),
EmailConfirmed = table.Column<bool>(nullable: false),
PasswordHash = table.Column<string>(nullable: true),
SecurityStamp = table.Column<string>(nullable: true),
ConcurrencyStamp = table.Column<string>(nullable: true),
PhoneNumber = table.Column<string>(nullable: true),
PhoneNumberConfirmed = table.Column<bool>(nullable: false),
TwoFactorEnabled = table.Column<bool>(nullable: false),
LockoutEnd = table.Column<DateTimeOffset>(nullable: true),
LockoutEnabled = table.Column<bool>(nullable: false),
AccessFailedCount = table.Column<int>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUsers", x => x.Id);
});
Esistono diversi modi per ottenere i dati correlati di un modello.
Quindi nel tuo caso puoi utilizzare il Eager loading
effettuando le seguenti operazioni:
context.Estates.Include(e => e.User).FirstOrDefault(m => m.Id == id);
Per maggiori informazioni leggere questo: caricamento dei dati correlati .
Modifica: un esempio per ottenere il Eager loading pattern
su IdentityUser
:
È possibile ottenere ciò tramite:
UserManager<User> _userManager
. Service
come nel Service/Repository Design Pattern
. Diciamo che hai scelto la prima opzione. Quindi puoi fare quanto segue:
var user = await _userManager.Users
.Include(u => u.Estates)
.FirstOrDefaultAsync(YOUR_CONDITION);