Getting user from DbContext after CreateAsync - entity-framework

I have a model called AppUser that inherits IdentityUser and I want to set some properties that exist only on AppUser. After creating the user via UserManager and getting the new Id I attempt to get the AppUser from DbContext however it is null and don't quite understand why.
How can I get the newly added AppUser?
...
var user = new IdentityUser { UserName = Input.Email, Email = Input.Email };
var result = await _userManager.CreateAsync(user);
var userId = await _userManager.GetUserIdAsync(user);
var appUser = _context.AppUsers.FirstOrDefault(x=>x.Id==userId); // <--- This is null

Related

Unit/Integration tests with inmemory database don't work with IQueryables

I'm trying to run some unit tests with inmemory database. I'm creating a new entity and then I'm checking if it exists or not. If I query as an Task<IEnumerable<Entity>> or a Task<Entity> with FindAsync(id),I get the model, but if I check with IQueryable<Entity> I'm getting null. Is there a restriction with InMemory Db with IQueryables? Because I feel that it only fetches it because of FindAsync();
Below is the code:
var model = await _context.User.FindAsync(id); returns model
var model = await GetUserModel(id);
Task<User> GetUserModel(int id)=>
await _context.User.FindAsync(id);
returns model
IQueryable<User> GetUser() =>
_context.User
.Include(u => u.Role)
.AsQueryable();
var model = await GetUser().AsNoTracking().FirstOrDefaultAsync(u => u.Id == id);
returns null
UnitTestSetup
protected static UserDbContext GetContext()
{
var options = new DbContextOptionsBuilder<UserDbContext>()
.UseInMemoryDatabase(databaseName: "TestDb")
.ConfigureWarnings(x => x.Ignore(InMemoryEventId.TransactionIgnoredWarning))
.Options;
return new UserDbContext(options);
}
UnitTest
[Fact]
public async Task GetUsers_ShouldReturnUsers()
{
//Arrange
var userService = new UserService(GetContext());
await userService.CreateUser(Helpers.CreateUser());
//Act
var viewModel = await userService.GetUsers();
//Assert
viewModel.Should().NotBeNullOrEmpty();
}
Edit:
After many tests it seems that my instinct is correct. If I use FirstOrDefaultAsync() it doesn't find the in memory created entity but if I use FindAsync() it does. If I compare a value of the created model with the model that FindAsync() fetches it returns true, so I know that my IQueryable method should be working.

DateTime Conversion error while using CodeFirst

I am using EF 6 Code First and creating a User and A Role and associating the user to the Role in Seed Method.
AppUserManager userManager = new AppUserManager(new UserStore<AppUser>(context));
AppRoleManager roleManager = new AppRoleManager(new RoleStore<AppRole>(context));
string roleName = "Administrators";
string userName = "Admin";
string password = "Admin#2016";
string email = "admin#admin.com";
if (roleManager.RoleExists(roleName))
{
roleManager.Create(new AppRole(roleName));
}
AppUser user = userManager.FindByName(userName);
if (user == null)
{
userManager.Create(new AppUser {UserName = userName, Email = email}, password);
user = userManager.FindByName(userName);
}
if (!userManager.IsInRole(user.Id, roleName))
userManager.AddToRole(user.Id, roleName);
But I am getting The conversion of a datetime2 data type to a datetime data type resulted in an out-of-range value.
The statement has been terminated error while executing the following statement.
userManager.Create(new AppUser {UserName = userName, Email = email}, password);
There is a field in IdentityUser base class called LockoutEndDateUtc it's type is DateTime? and in Database it is being correctly modeled as nullable.
I have seen other posts which instructs me to populate the date fields. But as it is nullable why should I populate it?
Yet I tried to initialize it like this:
LockoutEndDateUtc = DateTime.UtcNow.AddYears(3)
But still no luck.
I am not understanding why this error is popping up. Please help.
Thanks

How to seed a user at initializer with Identity asp.net mvc 5?

While working with database initializer, I can save a role and a user at my development database, but the password never works. I can not login.
This is the code, what is it lacking?
public class DevelopmentDbInitializer : System.Data.Entity. DropCreateDatabaseIfModelChanges<ApplicationDbContext>
{
protected override void Seed(ApplicationDbContext context)
{
string password = "1_Changeme";
string administrator = "Administrator";
string adminEmail = "admin#office.com";
// Role
if (!context.Roles.Any(role => role.Name == Utils.Constants.ROLE_ADMINISTRATOR))
{
var roleStore = new RoleStore<IdentityRole>(context);
var roleManager = new RoleManager<IdentityRole>(roleStore);
var adminRole = new IdentityRole { Name = Utils.Constants.ROLE_ADMINISTRATOR };
roleManager.Create(adminRole);
}
// User
if (!context.Users.Any(user => user.UserName == administrator))
{
var userStore = new UserStore<ApplicationUser>(context);
var userManager = new UserManager<ApplicationUser>(userStore);
var adminUser = new ApplicationUser { Email = adminEmail, UserName = administrator, PhoneNumber = "7144251556" };
userManager.Create(adminUser, password);
userManager.AddToRole(adminUser.Id, Utils.Constants.ROLE_ADMINISTRATOR);
}
}
}
User is at database, but there is something with the password. I also use a variant with hasher and is the same story. This code seems to work on older versions of Visual Studio an Entity.
Anything changed last year with VS and its libraries?
Thanks in advance.
Using Visual Studio 2015. I suppose it is Identity 2.0. Code came from different places at stackoverflow...

Entity Framework Updating with Stub causes Primary Key Violation

I have the following common tables with the relationships setup in a many to many fashion in my entity model:
Users - UserCodePK, UserName
UserGroups - UserCodeFK,GroupCodeFK
Groups - GroupCodePK,GroupDescription
My Code when trying to add a user:
public static string CreateUser(User user)
{
using (var dbContext = new DCSEntities())
{
User u = new User
{
UserCodePK = "NewUser",
txtUserName = "New User Name
};
u.Groups.Add(new UserGroup {GroupCode = "ADMIN"});
u.Groups.Add(new UserGroup {GroupCode = "SUPER"});
dbContext.Users.AddObject(user);
dbContext.SaveChanges();
}
}
The error that I'm getting is :
"Violation of PRIMARY KEY constraint 'PK_Groups'. Cannot insert duplicate key in object 'dbo.Groups'. The duplicate key value is (ADMIN)"
Basically saying that I'm trying to add the group "ADMIN", which already exists in that table. I thought that by using the stub as above, that I won't need to go the database to fetch the "ADMIN" group and add it to the User object.
Any advice on how to get rid of the error?
EDIT: My Completed Code Based on the Suggestions Below(I hope this is in the right place?)
UI Method
protected void CreateUser()
{
User user = new User();
user.UserCodePK = txtUserCode.Text;
user.UserName = txtUserName.Text;
List<UserGroup> userGroups = new List<UserGroup>();
for (int i = 0; i < chkListGroups.Items.Count; i++)
{
if (chkListGroups.Items[i].Selected == true)
{
userGroups.Add(new UserGroup { GroupCodePK = chkListGroups.Items[i].Value });
}
}
string userCode = BLL.UserFunctions.CreateUser(user, userGroups);
}
BLL Method
public static string CreateUser(User user, List<UserGroup> userGroups)
{
return UserDAL.CreateUser(user,userGroups);
}
DAL Method
public static string CreateUser(User user,List<UserGroup> userGroups)
{
using (var dbContext = new DCSEntities())
{
foreach (UserGroup g in userGroups)
{
var ug = new UserGroup { GroupCode = g.GroupCode };
dbContext.UserGroups.Attach(ug);
user.UserGroups.Add(ug);
}
dbContext.Users.AddObject(user);
dbContext.SaveChanges();
return user.UserCode;
}
}
It's a good idea to work with stubs. You only have to make sure that EF won't see them as new object, which you can do by attaching the stub to the context. Now EF will not give it the status Added.
var adminGroup = new UserGroup {GroupCode = "ADMIN"};
db.Groups.Attach(adminGroup);
...
u.Groups.Add(group);
If GroupCode is the primary key, EF will know how to associate the objects.

Include navigation property of navigation property in EF5/6

Here is my existing code, which fetches a user and gets his groups.
User user = new FetchUserByUsernameServiceCommand(Username, Context).Execute();
var groupList = user.JoinedGroups.ToList<Group>();
return groupList;
Each Group has a navigation property Image which has an ImageUrl.
I would like to Include the Image of each Group in the groupList, but Include is not available on the Lis<Group> groupList because it is not attached to a Context.
How can I include the Image navigation property for each Group?
You can either extend your command class and constructor to accept expressions for the navigation properties to include:
private string _userName;
private MyContext _context;
private Expression<Func<User, object>>[] _includes;
public FetchUserByUsernameServiceCommand(string userName,
MyContext context, params Expression<Func<User, object>>[] includes)
{
_userName = userName;
_context = context;
_includes = includes;
}
public User Execute()
{
IQueryable<User> query = _context.Users;
if (_includes != null)
{
foreach (var include in _includes)
query = query.Include(include);
}
return query.SingleOrDefault(u => u.UserName);
}
You would call this like so:
User user = new FetchUserByUsernameServiceCommand(
Username, Context, u => u.JoinedGroups.Select(g => g.Image))
.Execute();
var groupList = user.JoinedGroups.ToList();
return groupList;
Or you can use explicit loading:
User user = new FetchUserByUsernameServiceCommand(
Username, Context)
.Execute();
var groupList = Context.Entry(user).Collection(u => u.JoinedGroups).Query()
.Include(g => g.Image)
.ToList();
return groupList;
Note that only the first option is eager loading in the sense that user plus groups plus images are loaded together in a single database request. The second option (explicit loading) will run two database queries - the first one that only loads the User object in the command executor and the second one that loads groups plus images for that user.