CreateUserAndAccount and db.SaveChanges causes duplicate user entry - c#

I am working on a ASP.NET MVC 4 web application. The following code causes that the user will be created two times in the UserProfile Table.
...
WebSecurity.CreateUserAndAccount(UserName, Password);
var UserProfile = (from UserProf in _db.Users
where UserProf.UserName == UserName
select UserProf).FirstOrDefault();
UserCustomAttribute = new UserCustomAttribute();
UserCustomAttribute.UserProfile = UserProfile;
UserCustomAttribute.Name = "BelongsToAccountId";
UserCustomAttribute.Value = model.AgentModel.AccountId;
using (db = new xDb())
{
db.UserCustomAttributes.Add(UserCustomAttribute);
db.SaveChanges();
}
...
Using VS2012 debugging feature, I discovered that one entry is created when calling
WebSecurity.CreateUserAndAccount(UserName, Password);
And, the duplicate is created when calling
db.SaveChanges();
This is weird. I would expect that SaveChanges() is called in CreateUserAndAccount(...)?!
So, how to add something to database without duplicating created user?

Related

Inserting a row into Relational database table

I am very new to c# and asp.net mvc. I'm building a HR portal for our company where a user can submit a leave form among other things... So I'm using mssql as the database server and using Entity Frame work to communicate with it. I have 3 entities, user (Containing user details), permissions (the user permissions for allowing actions in the app) and then the leave form table (where the leave form details are stored). There is a one to many relationship between user - permission and then a one to many relationship between user-leave. I am not fazed about the permissions as that gets created when the user account is being created.
The problem I am facing is, how do I add a leave form for a specific user? Below is my controller code:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Leave(MasterViewModel model)
{
DocSubViewModel mv = model.DSModel;
int userId = Convert.ToInt32(Session["userID"]);
try
{
using (HrDcpDBContainer db = new HrDcpDBContainer())
{
var leave = db.leaves.Create();
leave.dateFrom = mv.DateFrom;
leave.dateSubmitted = DateTime.Now;
leave.dateTo = mv.DateTo;
leave.nrDays = mv.NrDays;
leave.reason = mv.SpecialLeave;
leave.TLApproval = null;
leave.TLApprovalDate = null;
leave.TLApprovalID = mv.TeamLeaderID;
leave.DMApprovalDate = null;
leave.DMApprovalID = mv.DepManagerID;
leave.DMApproval = null;
leave.type = mv.Type;
leave.user = userId;
db.leaves.Add(leave);
db.SaveChanges();
}
ViewBag.Message = "Leave Form submitted Successfully. You will be redirected shortly...";
return View("result");
}
catch (Exception ex)
{
ViewBag.Message = ex;
//ViewBag.Message = "Leave Form submitted Successfully. You will be redirected shortly...";
return View("result");
}
The problem comes in leave.user = userId;. It says:
Cannot implicitly convert int to Portal.Model.user
I can't seem to find out how to do this...
You're telling it to put the UserId where your leave model is asking for a User.
Your relationship requires a User to go in there, so you'll have to update your code a little bit:
using (HrDcpDBContainer db = new HrDcpDBContainer())
{
var leave = db.leaves.Create();
leave.user = db.users.First(x => x.Id == userId);
}
This will put reference to the actual user in the new leave record. If you go later and check it out you'll see a column in the leave table called user_Id that has an integer value in it and is set as a foreign key to the users table.
Note that this will error if no user exists having the specified Id value. If you anticipate this to be a problem, rather use .FirstOrDefault() instead of .First() and then account for the value being null before you add it to your new leave object.
That's expected since User is a object and not int. What you should be doing probably is leave.user.UserId = userId; instead [Assuming leave.user is of type User which has a UserId property]

Update custom membershipuser

I can't seem to find an answer for this anywhere. I'm using a custom membership provider and membership user with my own tables, which is appearing to be far too much hassle than it's worth. When updating a user record it appears that I need to update it's membership user instance as well, otherwise where I'm relying on data from membership user it isn't corresponding to the updated database.
I've created my own update membership user method, as the existing one only accepted it's own MembershipUser class:
public static void UpdateAccountUser(AccountUser accountUser)
{
// Custom MembershipUser
ToMembershipUser user = new ToMembershipUser(
"AccountUserMembershipProvider",
accountUser.FirstName + " " + accountUser.LastName,
accountUser.ID,
accountUser.Email,
"",
"",
true,
false,
DateTime.Now,
DateTime.MinValue,
DateTime.MinValue,
DateTime.MinValue,
DateTime.MinValue);
// Fill additional properties
user.ID = accountUser.ID;
user.Email = accountUser.Email;
user.FirstName = accountUser.FirstName;
user.LastName = accountUser.LastName;
user.Password = accountUser.Password;
user.MediaID = accountUser.MediaID;
user.Media = accountUser.Media;
user.Identity = accountUser.Identity;
user.CreatedAt = accountUser.CreatedAt;
user.UpdatedAt = accountUser.UpdatedAt;
UpdateCookie(user.Email);
}
private static void UpdateCookie(string email)
{
HttpCookie cookie = FormsAuthentication.GetAuthCookie(email, true);
var ticket = FormsAuthentication.Decrypt(cookie.Value);
// Store UserData inside the Forms Ticket with all the attributes
// in sync with the web.config
var newticket = new FormsAuthenticationTicket(ticket.Version,
ticket.Name,
ticket.IssueDate,
ticket.Expiration,
true, // always persistent
email,
ticket.CookiePath);
// Encrypt the ticket and store it in the cookie
cookie.Value = FormsAuthentication.Encrypt(newticket);
cookie.Expires = newticket.Expiration.AddHours(24);
HttpContext.Current.Response.Cookies.Set(cookie);
}
Now obviously this is just creating a new instance and not updating the existing one, which doesn't allow me to see the updated details without logging out and logging back in. Any ideas?
Edit
So I managed to find an example of someone else using their own custom update method, but all they appear to be doing is updating the database not the MembershipUser itself. I'm already doing this?!
I attempted to instead just update the FormsAuthenticationCookie and then when calling Membership.GetUser() I at least pass an updated User.Identity.Name, but to no avail, still old data even though database is updated. I've ran out of ideas...
This could possibly be a repeat of yesterday's question MembershipUser not getting updated result from database
I eventually found out the MembershipUser wasn't updating due to every time I calling GetUser() the query involved was using FirstOrDefault(). Turns out this caches the result rather than retrieving a fresh result. By adding AsNoTracking() to the query itself I now get the updated result, without having to even call UpdateUser().

Saving an entity to the DB in WinForms

I've looked at so many posts about this, but still haven't found the solution:
I'm using a winforms app that uses EntityFramework (6?). When I load the form I can read from the DB using the context (Entities). However, when I savechanges after adding a new entity, it doesn't persist to the db.
var c = new Card { Name = tbName.Text, Quantity = int.Parse(tbQuantity.Text) };
dbContext.Cards.Add(c);
dbContext.SaveChanges();
The dbContext is setup in the form constructor and is an instance of "LiquorTrackEntities".
LiquorTrackEntities dbContext;
public Form1()
{
InitializeComponent();
dbContext = new LiquorTrackEntities()
Reading from the db works:
var cards = dbContext.Cards.ToList();
I do this stuff all the time in asp.net MVC, but it isn't working in WinForms.. is there something special I have to do in winforms? I also know about the normal "using (var db = new LiquorEntitiesEntities())" convention, but I just want to get this functioning before I worry about convention.
Any ideas?
Just tried this to no avail:
var c = new Card { Name = tbName.Text, Quantity = int.Parse(tbQuantity.Text) };
dbContext.Cards.Attach(c);
dbContext.Entry(c).State = EntityState.Added;
dbContext.SaveChanges();
Just tried creating a new EDMX using EF5 instead.. same problem.
UPDATE:
SaveChanges does return a 1 when after adding a card. It stays in the context (if I reload my cards from the context, the new one is there..) but never makes it to the database.

Can't update an entity with Poco Code Generation Item

I have the following scenario:
the below 2 global variables in my page:
MainContext db = new MainContext();
User user = new User();
A method to fill the properties that is called on the button update:
private void FillProperties()
{
user.FirstName = txtFirstName.Text;
user.LastName = txtLastName.Text;
user.Email = txtEmail.Text;
}
on the button update i am doing the following:
FillProperties();
user.ID = Request.QueryString("userid");
db.SaveChanges();
but the record isn't been updated which i think is logical since the user variable isn't related to db object, but i a, not being able to do this:
db.Users.AddObject(user);
since AddObject isn't found in the db properties.
What can I do to update user?
Your answers are appreciated.
If you are using the DbContext API simply use
db.Entry(user).State = EntityState.Modified;
Where do you add your user to the DB?
If the user exists in the DB, in order to update it, you should do, for example:
user = db.Users.Where(x => x.ID == Request.QueryString("userid")).Single();
FillProperties();
db.SaveChanges();

EF 4 does not update database record on db.SaveChanges()

Hi I have this code snippet below:
Paypal paypal = new Paypal();
paypal.Invoice = transactionID;
paypal.TxnType = "";
paypal.CreateDate = DateTime.Now;
paypal.AmountPaid = payment;
paypal.PaymentStatusId = paymentStatus;
db.Paypals.Add(paypal);
db.SaveChanges();
// Order Does not Update
Order order = _orderRepository.GetOrderByOrderId(orderId);
order.OrderStatusId = OrderStatusConstant.Paid;
order.PurchasedDate = DateTime.Now;
order.LastModified = DateTime.Now;
order.PaypalIpnId = paypal.PaypalIpnId;
db.SaveChanges();
// Cart Does not Update
Cart cart = _cartRepository.GetCartByCartId(order.CartId);
cart.Completed = true;
db.SaveChanges();
Order and Cart entity does not update. But Paypal object is inserted. There are no errors or any exceptions thrown this is enclosed in a try..catch clause.
What seems to be the problem here? Repository codes returns object fine.
I see one thing in common here for Order and Cart and different for Paypal. Paypal is inserted using the context that is shown in the code, but Cart and Order are downloaded from the repository. Make sure that repository is using the same context.
So... when Insert work but Update doesn't, I look at the AutoDetectChange property (in context.Configuration).
If you don't want this tracking (mean AutoDetectChange = false), you have to set manually your modified entities as modified (EntityState).
(the insert works because the Add method modifies the object's entityState)

Categories