I have a many to many relationship between ApplicationUser and a model "Companies"
I want the signed in user to only be able to retrieve documents that are assigned to their company(s).
Using this linq statement
public IEnumerable<DocumentResult> GetDocuments()
{
var manager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
var user = manager.FindById(User.Identity.GetUserId());
return db.Documents
.Where(j => j.Company.Name == user.Companies)
.ToResults();
}
I am getting this
Operator '==' cannot be applied to operands of type 'string' and 'ICollection'
Models
public class Company
{
public Company()
{
Users = new HashSet<ApplicationUser>();
}
public int Id { get; set; }
public string Name { get; set; }
public ICollection<ApplicationUser> Users { get; set; }
}
ApplicationUser
public class ApplicationUser : IdentityUser
{
public ApplicationUser()
{
Companies = new HashSet<Company>();
}
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
return userIdentity;
}
public ICollection<Company> Companies { get; set; }
public string FullName { get; set; }
public string ProfilePicUrl { get; set; }
}
Consider using code like this:
db.Documents
.Where(j => user.Companies.Any(uc=>uc.Name == j.Company.Name));
.ToResults();
The error msg is clear.
user.Companies is a collection,j.Company.Name is string.
You can not use the "==" to compare string with the the different type.
Related
I'm doing several things in my method; they're necessary as far as I concerned, but optimizing the code isn't what this question is for.
In this method I'm creating a user, adding the user to a role, creating a Directorate and creating a record in a DirectorateUsers table to link the user to the new Directorate.
There's a few database operations here, so I wanted to try and reduce load on the database by only calling SaveChanges once.
It doesn't seem to be doing anything though; I'm not seeing a new directorate being added and the directorateuser isn't being added either. It creates the user and adds it to the specified role, however.
Is it possible to batch multiple changes to data in Entity Framework this way or do I have to await db.SaveChangesAsync() every time I do something like add or update a record?
[HttpPost]
public async Task<ActionResult> Create([Bind(Include = "MunicipalityId,DirectorateName,UserEmailAddress, UserPassword")] RegisterDirectorateViewModel model)
{
try
{
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.UserEmailAddress, Email = model.UserEmailAddress };
var createUserResult = await UserManager.CreateAsync(user, model.UserPassword);
if (createUserResult.Succeeded)
{
// Add the user to the directorate role.
await UserManager.AddToRoleAsync(user.Id, nameof(SystemRoles.Directorate));
// Generate the directorate and add the user to it.
var municipality = await db.Municipalities.FindAsync(model.MunicipalityId);
var directorate = new Directorate
{
Action = MetaAction.Create,
ActionBy = user,
ActionDate = DateTime.Now,
Municipality = municipality,
Name = model.DirectorateName
};
db.Directorates.Add(directorate);
var directorateUser = new DirectorateUser
{
Directorate = directorate,
User = user
};
db.DirectorateUsers.Add(directorateUser);
// Expire the token so that it can't be used again.
municipality.TokenExpiryDate = DateTime.Now;
db.Entry(municipality).State = EntityState.Modified;
await db.SaveChangesAsync();
// Sign in the user and redirect to the dashboard.
await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
return RedirectToAction("Index", "Dashboard");
}
}
return View(model);
}
catch (Exception ex)
{
TempData["err"] = ex;
return RedirectToAction("Create");
}
}
EDIT
Here's extra models per comments...
public class Directorate
{
public int Id { get; set; }
public string Name { get; set; }
public virtual Municipality Municipality { get; set; }
public ApplicationUser ActionBy { get; set; }
public DateTime ActionDate { get; set; }
public MetaAction Action { get; set; }
}
public class DirectorateUser
{
public int Id { get; set; }
public virtual Directorate Directorate { get; set; }
public virtual ApplicationUser User { get; set; }
}
public class SubdirectorateUser
{
public int Id { get; set; }
public virtual Subdirectorate Subdirectorate { get; set; }
public virtual ApplicationUser User { get; set; }
}
You need many to many relationship. Though you have one User table and Directorates table so DirectorateUsers table contains Many-To-Many relationship between User/ApplicationUser and Directorates. So you have to Customize the Model for Many to Many Relationship.
public class ApplicationUser
{
public ApplicationUser()
{
this.Directorates = new HashSet<Directorate>();
}
....
public virtual ICollection<Directorate> Directorates { get; set; }
}
And the Directorate Model has
public class Directorate
{
public Directorate()
{
this.Users = new HashSet<ApplicationUser>();
}
public virtual ICollection<ApplicationUser> Users{ get; set; }
}
Now the DbContext class looks like...
public class AppDBContext : DBContext
{
public AppDBContext() : base("DefaultConnectionString")
{
}
public DbSet<ApplicationUser> Users{ get; set; }
//or public DbSet<User> Users{ get; set; } //if ApplicationUser doesn't work
public DbSet<Directorate> Directorates{ get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
//Configure a Many-to-Many Relationship using Fluent API
modelBuilder.Entity<User>() //or ApplicationUser
.HasMany<Directorate>(s => s.Directorates)
.WithMany(c => c.Users)
.Map(cs =>
{
cs.MapLeftKey("UserId");
cs.MapRightKey("DirectorateId");
cs.ToTable("DirectorateUser");
});
}
}
This mapping create a good relationship. please check the below link for many to many relationship.
https://www.entityframeworktutorial.net/code-first/configure-many-to-many-relationship-in-code-first.aspx
Now check your code db.SaveChangesAsync(); or without await simply db.SaveChanges()..
Hope this can work.Remember you have to mapping your Object in correct way.
I see that when you are creating the Directorate and the DirectorateUser you are using the "user" variable, which may not be referring the one in the database.
Using the following variable instead of "user" to create the Directorate and the DirectorateUser may solve the issue.
var userDb = await _userManager.FindByNameAsync(user.UserName)
For me, the issue points to something at this.
db.Entry(municipality).State = EntityState.Modified;
await db.SaveChangesAsync();
This will only initiate saving changes related to municipality.
but, I think you should have something like this.
//set all objects that need to be updated in a modified state
db.Entry(municipality).State = EntityState.Modified;
db.Entry(directorate).State = EntityState.Modified;
db.Entry(directorateUser).State = EntityState.Modified;
//finally save all the changes to the database.
await db.SaveChangesAsync();
This is how, I would do it.
I see that you are using UserManager to access an IdentityDbContext. The Identity framework uses an instance of IUserStore to glue the two together. But as you've noticed, every operation immediately saves changes.
The default implementation, UserStore already has a boolean property AutoSaveChanges to prevent saving on every operation, however there doesn't seem to be an obvious way to access this property.
You could either replace the IUserStore service with your own implementation (as per UserManager's AutoSaveChanges in .NET Core 2.1);
public class CustomUserStore : UserStore<IdentityUser>
{
public CustomUserStore(ApplicationDbContext context)
: base(context)
{
AutoSaveChanges = false;
}
}
services.AddScoped<IUserStore<IdentityUser>, CustomUserStore>();
Though you would then need to ensure that all UserManager / SigninManager calls are followed by another explicit save.
Or you could add IUserStore as a dependency, assume that it is an instance of UserStore and change the AutoSaveChanges value around your method;
private UserStore<IdentityUser, IdentityRole, DbContext> store;
public Controller(IUserStore<IdentityUser> store)
{
this.store = store as UserStore<IdentityUser, IdentityRole, DbContext>;
}
public async Task<ActionResult> Create(...){
try{
store.AutoSaveChanges = false;
...
}finally{
store.AutoSaveChanges = true;
}
}
Note that which UserStore generic type you need, depends on which IdentityContext generic type you are using.
I am trying to get into MVC with EntityFramework.
Its going quite well, but there is something i cannot figure out.
I have 3 models, BierlijstEntry, Huis and ApplicationUser.
I have tried to implement the following relations
ApplicationUser * ... * Huis's
ApplicationUser 1...* BierlijstEntry (BierlijstEntry has one ApplicationUser)
Huis 1...* BierlijstEntry (BierlijstEntry has one Huis)
namespace BierlijstMVC
{
public partial class DatabaseContext : IdentityDbContext<ApplicationUser>
{
public DatabaseContext()
: base("DBContext")
{
}
public static DatabaseContext Create()
{
return new DatabaseContext();
}
public virtual DbSet<BierlijstEntry> BierlijstEntries { get; set; }
public virtual DbSet<Huis> Huizen { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Huis>()
.HasMany(x => x.Users)
.WithMany(x => x.Huis);
modelBuilder.Entity<Huis>()
.HasMany(e => e.BierlijstEntry)
.WithRequired(e => e.Huis);
modelBuilder.Entity<ApplicationUser>()
.HasMany(x => x.BierlijstEntries)
.WithRequired(x => x.User);
}
}
}
The models are defined as follows:
BierlijstEntry
namespace BierlijstMVC.Models
{
public class BierlijstEntry
{
[Key]
public int BierlijstEntryId { get; set; }
public int Gedronken { get; set; }
public int Gehaald { get; set; }
public int HuisId { get; set; }
public string UserId { get; set; }
public virtual Huis Huis { get; set; }
public virtual ApplicationUser User { get; set; }
}
}
Huis
namespace BierlijstMVC.Models
{
public class Huis
{
public Huis()
{
Users = new List<ApplicationUser>();
BierlijstEntry = new List<BierlijstEntry>();
}
[Key]
public int HuisId { get; set; }
[Required]
public string Huisnaam { get; set; }
public virtual ICollection<ApplicationUser> Users { get; set; }
public virtual ICollection<BierlijstEntry> BierlijstEntry { get; set; }
}
}
ApplicationUser
namespace BierlijstMVC.Models
{
[Table("AspNetUsers")]
public partial class ApplicationUser : IdentityUser
{
public ApplicationUser()
{
Huis = new List<Huis>();
BierlijstEntries = new List<BierlijstEntry>();
}
public string Nickname { get; set; }
public virtual ICollection<Huis> Huis{ get; set; }
public virtual ICollection<BierlijstEntry> BierlijstEntries { get; set; }
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
userIdentity.AddClaim(new Claim("Nickname", this.Nickname.ToString()));
return userIdentity;
}
}
}
Now My register gives me three fields: Email, Password, Nickname (ApplicationUser) and Huisnaam (Huis)
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.Email, Email = model.Email, Nickname = model.Nickname};
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
var db = new DatabaseContext();
if (!db.Huizen.Any(x => x.Huisnaam.Equals(model.HouseName)))
{
var huis = new Huis()
{
Huisnaam = model.HouseName,
};
BierlijstEntry entry = new BierlijstEntry();
entry.Huis = huis;
entry.User = user;
Huis.BierlijstEntry.Add(entry);
Huis.Users.Add(user);
user.Huis.Add(huis);
user.BierlijstEntries.Add(entry);
db.Huizen.AddOrUpdate(huis);
db.BierlijstEntries.AddOrUpdate(entry);
try
{
db.SaveChanges();
}
catch (DbEntityValidationException ex)
{
** SNIP: Catch exception
}
}
await SignInManager.SignInAsync(user, isPersistent:false, rememberBrowser:false);
string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
UserManager.EmailService = new EmailService();
await UserManager.SendEmailAsync(user.Id, "Confirm your account", "Please confirm your account by clicking here");
return RedirectToAction("Index", "Home");
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}
The first bit of code is the standard creation of a user. The code breaks as soon as it hits db.SaveChanges().
I Assume that due to the relations a user gets added twice. The error I'm getting is that I'm trying adding a user name which already exists. The CreateUser indeed adds it the first time, but SaveChanges for some reason too. HoweverI would not know why and where. I would like some help on this
Edit
I do have a HuisApplicationUser table in my database, which is mapped as
ApplicationUser * ... * Huis but for some reason it is not getting added in that table, but added as a new user
This line is going to add the same user you already added.
Huis.Users.Add(user);
Do you have another table named UserHuis or something similar for the many to many relationship? Depending on what version of asp.net you are using it could be mapped using something similar to this.
modelBuilder.Entity<Huis>()
.HasMany<Users>(u => u.Users)
.WithMany(h => h.Huis)
.Map(hu =>
{
hu.MapLeftKey("HuisId");
hu.MapRightKey("UserId");
hu.ToTable("UserHuis");
});
I'm trying to use the new ASP.NET Identity in my MVC5 application, specifically I'm trying to integrate ASP.NET Identity into an existing database. I've already read the questions/answers on SO pertaining to DB First and ASP.NET Identity, and having followed all the recommendations I still can't add roles to my database, although I have no problems adding users. Here's my code:
var context = new PayrollDBEntities();
var roleManager = new RoleManager<AspNetRole>(new RoleStore<AspNetRole>(context));
bool roleExists = roleManager.RoleExists(roleDto.Name);
if (roleExists){
return false;
}
var role = new AspNetRole(roleDto.Name){
Name = roleDto.Name,
};
IdentityResult result = roleManager.Create(role);//Getting exception here
At the last line of code I get an exception of type 'System.InvalidOperationException': The entity type IdentityRole is not part of the model for the current context.
Here is my context:
public partial class PayrollDBEntities : IdentityDbContext
{
public PayrollDBEntities()
: base("name=PayrollDBEntities")
{
}
public virtual DbSet<AspNetRole> AspNetRoles { get; set; }
public virtual DbSet<AspNetUserClaim> AspNetUserClaims { get; set; }
public virtual DbSet<AspNetUserLogin> AspNetUserLogins { get; set; }
public virtual DbSet<AspNetUser> AspNetUsers { get; set; }
......
}
My AspNetUser and AspNetRole classes derive from IdentityUser and IdentityRole respectively, but I'm still getting that exception. Here is my database diagram:
Any help would be greatly appreciated.
You have to specify during the creation of User Store that AspNetRole is used instead of IdentityRole. You can achieve this by using the UserStore class with 6 type parameters:
new UserStore<AspNetUser, AspNetRole, string, IdentityUserLogin, IdentityUserRole, IdentityUserClaim>(new PayrollDBEntities());
This indicates changes at User Manager creation as well. Here is a simplified example about the creation of needed instances:
public class AspNetUser : IdentityUser { /*customization*/ }
public class AspNetRole : IdentityRole { /*customization*/ }
public class PayrollDBEntities : IdentityDbContext //or : IdentityDbContext <AspNetUser, AspNetRole, string, IdentityUserLogin, IdentityUserRole, IdentityUserClaim>
{
}
public class Factory
{
public IdentityDbContext DbContext
{
get
{
return new PayrollDBEntities();
}
}
public UserStore<AspNetUser, AspNetRole, string, IdentityUserLogin, IdentityUserRole, IdentityUserClaim> UserStore
{
get
{
return new UserStore<AspNetUser, AspNetRole, string, IdentityUserLogin, IdentityUserRole, IdentityUserClaim>(DbContext);
}
}
public UserManager<AspNetUser, string> UserManager
{
get
{
return new UserManager<AspNetUser, string>(UserStore);
}
}
public RoleStore<AspNetRole> RoleStore
{
get
{
return new RoleStore<AspNetRole>(DbContext);
}
}
public RoleManager<AspNetRole> RoleManager
{
get
{
return new RoleManager<AspNetRole>(RoleStore);
}
}
}
After a few days of trying to get this to work in a clean manner, I've come to the conclusion that if you're using Database first and want to integrate ASP.NET Identity into your app, by far the easiest and cleanest solution is to create your own membership provider by overriding ASP.NET Identity. It's actually pretty easy, so far I've implemented UserStore and RoleStore to my liking. I've added columns/relations specific to my domain in my database, and whenever I create a user or a role, I take care of my database commits by adding the required relations. My UserStore implementation is quite similar to this. My RoleStore implementation is something like this:
public class ApplicationRoleStore : IRoleStore<ApplicationRoleDTO>
{
private PayrollDBEntities _context;
public ApplicationRoleStore() { }
public ApplicationRoleStore(PayrollDBEntities database)
{
_context = database;
}
public Task CreateAsync(ApplicationRoleDTO role)
{
if (role == null)
{
throw new ArgumentNullException("RoleIsRequired");
}
var roleEntity = ConvertApplicationRoleDTOToAspNetRole(role);
_context.AspNetRoles.Add(roleEntity);
return _context.SaveChangesAsync();
}
public Task DeleteAsync(ApplicationRoleDTO role)
{
var roleEntity = _context.AspNetRoles.FirstOrDefault(x => x.Id == role.Id);
if (roleEntity == null) throw new InvalidOperationException("No such role exists!");
_context.AspNetRoles.Remove(roleEntity);
return _context.SaveChangesAsync();
}
public Task<ApplicationRoleDTO> FindByIdAsync(string roleId)
{
var role = _context.AspNetRoles.FirstOrDefault(x => x.Id == roleId);
var result = role == null
? null
: ConvertAspNetRoleToApplicationRoleDTO(role);
return Task.FromResult(result);
}
public Task<ApplicationRoleDTO> FindByNameAsync(string roleName)
{
var role = _context.AspNetRoles.FirstOrDefault(x => x.Name == roleName);
var result = role == null
? null
: ConvertAspNetRoleToApplicationRoleDTO(role);
return Task.FromResult(result);
}
public Task UpdateAsync(ApplicationRoleDTO role)
{
return _context.SaveChangesAsync();
}
public void Dispose()
{
_context.Dispose();
}
private ApplicationRoleDTO ConvertAspNetRoleToApplicationRoleDTO(AspNetRole aspRole)
{
return new ApplicationRoleDTO{
Id = aspRole.Id,
EnterpriseId = aspRole.EnterpriseId,
Name = aspRole.Name
};
}
private AspNetRole ConvertApplicationRoleDTOToAspNetRole(ApplicationRoleDTO appRole)
{
return new AspNetRole{
Id = appRole.Id,
EnterpriseId = appRole.EnterpriseId,
Name = appRole.Name,
};
}
}
And my ApplicationRoleDTO:
public class ApplicationRoleDTO : IRole
{
public ApplicationRoleDTO()
{
Id = Guid.NewGuid().ToString();
}
public ApplicationRoleDTO(string roleName)
: this()
{
Name = roleName;
}
public string Id { get; set; }
public string Name { get; set; }
public Guid EnterpriseId { get; set; }
}
I also found these 2 articles pretty helpful:
Overview of Custom Storage Providers for ASP.NET Identity
Implementing a Custom MySQL ASP.NET Identity Storage Provider
I'll explain here with the code exampels :).
The trick is, they are already in the IdentityDbContext (AspNetRoles, AspNetUserClaims, AspNetUsers, ....)
In the IdentityModel you will see ApplicationUser is empty at the top. If you want to customize these users or roles, just add properties here and then update your database via the console
Example of my context
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection")
{
}
public DbSet<Request> Requests { get; set; }
public DbSet<Reservation> Reservations { get; set; }
public DbSet<PriceType> PriceTypes { get; set; }
public DbSet<Product> Products { get; set; }
public DbSet<Price> Prices { get; set; }
public DbSet<GuestbookPost> Posts { get; set; }
public DbSet<Count> Counts { get; set; }
public DbSet<Invoice> Invoices { get; set; }
public DbSet<InvoiceLine> InvoiceLines { get; set; }
...
}
So no application user is defined here, but I did add more properties to it, example:
public class ApplicationUser : IdentityUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string GroupName { get; set; }
public string Email { get; set; }
[StringLength(15)]
public string Phone { get; set; }
public string Remark { get; set; }
public DateTime? BirthDate { get; set; }
public DateTime ValidFrom { get; set; }
public DateTime ValidUntil { get; set; }
public string Street { get; set; }
public string ZipCode { get; set; }
public string City { get; set; }
public virtual ICollection<Request> Requests { get; set; }
}
I know this is an old question, but just in case someone else is having a hard time adding roles/users when they modified asp identity to use numeric primary keys (int/long) instead of the default string for the Identity Roles, so if you have changed the IdentityUserRole in IdentityModels.cs to something like this:
public class Role : IdentityRole<long, UserRole>
{
public Role() { }
public Role(string name) { Name = name; }
}
You have to use the class Role instead of the default IdentityRole when constructing the RoleManager, so your code should be like this:
public static void RegisterUserRoles()
{
ApplicationDbContext context = new ApplicationDbContext();
var RoleManager = new RoleManager<Role, long>(new RoleStore(context));
if (!RoleManager.RoleExists("Administrador"))
{
var adminRole = new Role {
Name = "Administrador",
};
RoleManager.Create(adminRole);
}
}
So this should populate your database properly, I think all experienced ASP programmers already know this, but for others this could take some time to figure out.
I solved with a different way.
First I splited in two different Projects and Contexts.
My project that Handle the Identity has this context:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>, IDisposable
{
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
This is my ApplicationUser:
public class ApplicationUser : IdentityUser
{
//Put here the extra properties that Identity does not handle
[Required]
[MaxLength(150)]
public string Nome { get; set; }
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
return userIdentity;
}
}
And my ApplicationUserManager looks like this:
public class ApplicationUserManager : UserManager<ApplicationUser>
{
public ApplicationUserManager(IUserStore<ApplicationUser> store)
: base(store)
{
//Setting validator to user name
UserValidator = new UserValidator<ApplicationUser>(this)
{
AllowOnlyAlphanumericUserNames = false,
RequireUniqueEmail = true
};
//Validation Logic and Password complexity
PasswordValidator = new PasswordValidator
{
RequiredLength = 6,
RequireNonLetterOrDigit = false,
RequireDigit = false,
RequireLowercase = false,
RequireUppercase = false,
};
//Lockout
UserLockoutEnabledByDefault = true;
DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5);
MaxFailedAccessAttemptsBeforeLockout = 5;
// Providers de Two Factor Autentication
RegisterTwoFactorProvider("Código via SMS", new PhoneNumberTokenProvider<ApplicationUser>
{
MessageFormat = "Seu código de segurança é: {0}"
});
RegisterTwoFactorProvider("Código via E-mail", new EmailTokenProvider<ApplicationUser>
{
Subject = "Código de Segurança",
BodyFormat = "Seu código de segurança é: {0}"
});
//Email service
EmailService = new EmailService();
// Definindo a classe de serviço de SMS
SmsService = new SmsService();
var provider = new DpapiDataProtectionProvider("Braian");
var dataProtector = provider.Create("ASP.NET Identity");
UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(dataProtector);
}
}
I hope that this helps someone.
This solution was from this article:
Eduardo Pires - But it is in Portuguese
I fixed this issue by changing the web.config DefaultConnection connectionString property so it points to the new SQLServer database
For my homework I need to get the data with a c# application using Entity Framework out of a SQL database.
The problem is that I have no idea what I am doing wrong.
My class:
public class Organisation
{
public int Id { get; set; }
public string Name { get; set; }
public Organisation(int Id, string Name)
{
this.Id = Id;
this.Name = Name;
}
public class OrganisationContext : DbContext
{
public DbSet<Organisation> Organisations { get; set; }
}
public static Organisation Find(int id) {
using (var context = new OrganisationContext())
{
// Query for all blogs with names starting with B
var organisation = from b in context.Organisations
where b.Id = id
select b;
return organisation;
}
}
}
My user class. I use Identity.
public class ApplicationUser : IdentityUser
{
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
return userIdentity;
}
public string Firstname { get; set; }
public string Interjunction { get; set; }
public string Lastname { get; set; }
public int OrganisationId { get; set; }
public virtual Organisation Organisation
{
get
{
return Organisation.Find(OrganisationId);
}
}
public int Role { get; set; }
public string DisplayName
{
get
{
string dspFirstname = string.IsNullOrWhiteSpace(this.Firstname) ? "" : this.Firstname;
string dspInterjunction = string.IsNullOrWhiteSpace(this.Interjunction) ? "" : this.Interjunction + " ";
string dspLastname = string.IsNullOrWhiteSpace(this.Lastname) ? "" : this.Lastname;
return string.Format("{0} {1}{2}", dspFirstname, dspInterjunction, dspLastname);
}
}
}
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
I am searching and trying to understand it for a while but how do I convert a var to an organisation model? Or am I missing an important peace of code?
Ok. In your method you want to return single Organization object:
public static Organisation Find(int id)
But your LINQ query actually returns a collection of objects:
using (var context = new OrganisationContext())
{
// Query for all blogs with names starting with B
var organisation = from b in context.Organisations
where b.Id = id
select b;
return organisation;
}
In this case you are filtering organization by primary key and there is no situation when this query returns more then 1 row. Then you can just call SingleOrDefault():
var organisation = (from b in context.Organisations
where b.Id = id
select b).SingleOrDefault();
return organisation;
Also, you can use Find method from DbSet class:
using (var context = new OrganisationContext())
{
// Query for all blogs with names starting with B
var organisation = context.Organisations.Find(id)
return organisation;
}
One of the common requirements for entities in EF is parameterless constructor. So, you need to remove existed constroctor for Organization class or add another one:
public Organization() { }
I'm currently writing a small test application to understand how IdentityUser works.
I've created a MyUser class that inherits from IdentityUser. The only additional property on my custom user class is a collection of my Book class.
I've created methods on the controller that successfully store new users to the database and associated Books. The problem is when I try to retrieve a user, the Books collection for that user is not populated - it's always null.
When I check the database I can see that a Book is stored in the database with an associated User ID however I can't seem to retrieve this collection.
Here is what I have so far:
Book.cs:
public class Book
{
public int Id { get; set; }
public string Isbn { get; set; }
public string Title { get; set; }
public string Author { get; set; }
}
MyUser.cs:
public class MyUser : IdentityUser
{
public IList<Book> Books { get; set; }
}
MyAppContext.cs:
public class MyAppContext : IdentityDbContext<MyUser>
{
public MyAppContext() : base("MyApp")
{
}
public DbSet<Book> Books { get; set; }
}
AuthRepository:
public class AuthRepository : IDisposable
{
private MyAppContext _ctx;
private UserManager<MyUser> _userManager;
public AuthRepository()
{
_ctx = new MyAppContext();
_userManager = new UserManager<MyUser>(new UserStore<MyUser>(_ctx));
}
public async Task<IdentityResult> RegisterUser(RegistrationModel userModel)
{
MyUser user = new MyUser();
user.UserName = userModel.UserName;
var result = await _userManager.CreateAsync(user, userModel.Password);
return result;
}
public async Task<IdentityResult> UpdateUser(MyUser userModel)
{
var result = await _userManager.UpdateAsync(userModel);
return result;
}
public async Task<MyUser> FindUser(string userName, string password)
{
var user = await _userManager.FindAsync(userName, password);
return user;
}
public async Task<MyUser> GetUser(string userName)
{
var user = await _userManager.FindByNameAsync(userName);
return user;
}
public void Dispose()
{
_ctx.Dispose();
_userManager.Dispose();
}
}
I figured maybe within the GetUser() method I could manually retrieve all books from the Book table with _ctx.Books.Where(b => b.MyUser_id == user.Id) however intellisense isn't even giving me the MyUser_Id property on the Books table.
I'm not really sure how to go about this. All I want to do is load all the associated books for a user automatically but I'm not sure how to do this. Any ideas?
Thanks
Your class for Book doesn't include user information for the foreign key reference. Try adding
[ForeignKey("UserId")]
public MyUser User { get; set; }
to the Book class definition.
When you get the users with the query
_ctx.Users.Include(u=> u.Books)
The books for each user should be included.