I have a simple many-to-one relationship:
public class Company
{
public IEnumerable<User> Users { get; set; }
public int Id { get; set; }
}
public class User
{
public int CompanyId { get; set; }
[Required]
public Company Company { get; set; }
public int Id { get; set; }
}
I also tried to define my user as the following (without success):
public class User
{
[Required]
[ForeignKey("Company")]
public int CompanyId { get; set; }
public virtual Company Company { get; set; }
public int Id { get; set; }
}
I have the following method to add a new User to a Company:
public async Task<bool> Add(User user)
{
try
{
await this.context.Set<User>().AddAsync(user);
await this.context.SaveChangesAsync();
return true;
}
catch (Exception)
{
return false;
}
}
I call this method like this:
var company = await this.companyService.Get(1); // this works
if (company == null)
{
return;
}
await this.userService.Add(
new User
{
CompanyId = company.Id,
Company = company, // I also tried to remove this line - no effect
});
My DbContext looks like this:
public class AppContext : IdentityDbContext
{
public AppContext(DbContextOptions<AppContext> options)
: base(options)
{
}
public DbSet<Company> Company { get; set; }
public DbSet<User> User { get; set; }
}
Now that I have explained the scenario, here's the problem. When I add a user to a company, all entries are removed. What do I mean by "removed"? The entire table "user" is empty, without any entries. Before I add the user and inspect the company
I can see all users. If I fetch the company again after the insertion, the property Users
returns an empty list (not null). This also affects deletion and updating of the value. I have been sitting here with this issue for 3 days and have absolutely no idea what I am doing wrong.
CodePudding user response:
Try this classes (you can ommit data annotation if you use ef core 5 )
public class User
{
[Key]
public int Id { get; set; }
[Required]
public int? CompanyId { get; set; }
[ForeignKey(nameof(CompanyId ))]
[InverseProperty("Users")]
public virtual Company Company { get; set; }
}
public class Company
{
[Key]
public int Id { get; set; }
[InverseProperty(nameof(User.Company))]
public virtual ICollection<User> Users { get; set; }
}
and code
var company = await this.companyService.Get(1);
await this.userService.Add(new User { CompanyId = company.Id});
public async Task<bool> Add(User user)
{
try
{
context.Set<User>().Add(user);
await context.SaveChangesAsync();
return true;
}
catch (Exception)
{
return false;
}
}
CodePudding user response:
After 30 hours of debugging I found the problem. It had nothing to do with the EF (which I expected to a certain degree, since I literally copy and pasted the entire documentation 5 times).
Maybe someone has a similar problem, so I post my answer here, but beware that this is highly specific to my use case.
I store my currently logged in user in the ProtectedSessionStorage like this:
await this.protectedSessionStorage.SetAsync("user", await this.userService.Get(id));
For whatever reason (I searched for this for an additional 2 hours), some of my properties are ignored and not stored correctly (namely the property Company.Users
), even though I do not use any annotations which explain this behavior. When I then load this exact user again, for some other unknown reason, the EF thinks that (because the Company.Users
property is missing) the company does not have any users. Again, this behavior is not described in the documentation and I found literally no one with that specific problem, so I might have done something which describes this behavior.
The solution: Take Json.NET from Newtonsoft, serialize it and then store the serialized string in the protected session storage. I literally just changed this and everything works as intended. Of course I had to deserialize everything when I access the storage.
await this.protectedSessionStorage.SetAsync("user", JsonConvert.SerializeObject(await this.userService.Get(id)));