When i'll try to create a new timeSlot i want to add the userId. It save all, but the UserId is a new one and the code also create a new user instead of just set the foreign key.
During the debug user.Id is correct and also timeSlot.User.Id is correct.
protected override bool BeforeSaveEntity(EntityInfo entityInfo)
{
// return false if we don’t want the entity saved.
if (entityInfo.Entity.GetType() == typeof(TimeSlot)
&& entityInfo.EntityState == EntityState.Added)
{
var timeSlot = (TimeSlot)entityInfo.Entity;
var user = uow.Users.GetById(userId);
timeSlot.User = user;
return true;
}
else
{
return true;
}
}
Related
I have the following table
Permissions Table
On login, I am getting the values of ProductEdit, ProductView, ProductDelete for that logged in user and storing them in session to be used later for custom authorization on some actions within the project. This is achived with the following code (note var permissionJoin)
if (usr != null)
{
Session["OperatorId"] = usr.OperatorId.ToString();
Session["Username"] = usr.Username.ToString();
Session["GroupId"] = usr.GroupId.ToString();
var permissionsJoin = from up in db.UserPermissions
join op in db.Operators
on up.GroupId equals usr.GroupId
select new UserPermissionData
{ UserGroupId = up.GroupId, P_Edit = up.ProductEdit, P_Create = up.ProductCreate, P_Delete = up.ProductDelete };
Session["ProductPermission"] = permissionsJoin.ToList<UserPermissionData>();
return RedirectToAction("LoggedIn");
}
I am using a named class [UserPermissionData - that has the four properties I need] to store these values. The results are getting stored in the session fine.
Now onto my authorization class were I need to extract those values and check - if the user has the permission for a particular. I have the following code
public class AuthorizeProductEdit : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
//lets get the session values of the current user's permissions
var userP = (UserPermissionData)HttpContext.Current.Session["ProductPermission"];
var editProduct = userP.P_Edit;
if (editProduct.ToString() == "Y")
{
return true;
}
else
{
return false;
}
}
}
at the point of clicking an edit action for the logged in user I am getting an "Unable to cast object of type" error [see image]
Error Image
How can I cast back that query to be able to use if for checking my permissions.
You store in Session is a List<UserPermissionData> so you must cast session value to List<UserPermissionData>
var userP = HttpContext.Current.Session["ProductPermission"] as List<UserPermissionData>;
if (userP == null) return false;
return userP.Any(x => x.P_Edit.ToString() == "Y");
I am trying to update entity but the entity framework do not save changes
this is my code
public bool updateUser(user CUser)
{
CurrentUser = (CustomPrincipal)HttpContext.Current.User;
user userToBeUpdated = context.users.Where(user => user.user_id == CurrentUser.Id).FirstOrDefault();
userToBeUpdated = CUser;
context.SaveChanges();
return true;
}
does there anything wrong in my code?
Update
public bool updateUser(user CUser)
{
CurrentUser = (CustomPrincipal)HttpContext.Current.User;
user userToBeUpdated = context.users.Where(user => user.user_id == CurrentUser.Id).FirstOrDefault();
CUser.user_id = userToBeUpdated.user_id;
CUser.date_created = userToBeUpdated.date_created;
if (CUser.Password == "hidden")
CUser.Password = userToBeUpdated.Password;
else
CUser.Password = new Hash().GetBcryptHashedPassword(CUser.Password);
if (CUser.UDTO.File.ContentLength > 0)
{
FileHelper ProfilePicture = new FileHelper(CUser.UDTO.File, "jpg,jpeg,png", 5, true, 500, 500);
if (!checkUserPersonalImage(CUser.UDTO.File, CUser, ProfilePicture, CurrentUser))
{
return false;
}
CUser.PersonalImage = ProfilePicture.uploadFile();
}
else
{
CUser.PersonalImage = userToBeUpdated.PersonalImage;
}
if (!checkRoleValidity(CUser, CurrentUser, false, false))
{
return false;
}
if (!checkDepartmentValidity(CUser, CurrentUser, false, false))
{
return false;
}
userToBeUpdated = CUser;
context.Entry(userToBeUpdated).State = System.Data.Entity.EntityState.Modified;
context.SaveChanges();
new UserHelperMethods().updateUserHolderLists(CurrentUser.Company, CUser);
CUser.UDTO.RedirectTo = "AddNewUser";
CUser.UDTO.Message="<div class='success'>User has been updated successfully</div>";
CUser.UDTO.Company = CurrentUser.Company;
return true;
}
this is the complete function and I got the following error
Attaching an entity of type 'workflow.Models.user' failed because
another entity of the same type already has the same primary key
value. This can happen when using the 'Attach' method or setting the
state of an entity to 'Unchanged' or 'Modified' if any entities in the
graph have conflicting key values. This may be because some entities
are new and have not yet received database-generated key values. In
this case use the 'Add' method or the 'Added' entity state to track
the graph and then set the state of non-new entities to 'Unchanged' or
'Modified' as appropriate.
I used to update a field in the entity by changing its value and then call thecontext.SaveChanges() for example userToBeUpdated.X = 15; context.SaveChanges(); and then it saves the changes so I think that userToBeUpdated = CUser changes works the same like userToBeUpdated .X = 15
You are quite wrong in assuming that userToBeUpdated.X=15 and userTobeUpdated=CUser does the same thing. The original object that the userToBeUpdated variable referenced is still tracked by EF. After that you change the reference of the userToBeUpdated variable to an instance of another object and attach it to the DbContext. The dbcontext now tries to track two objects: the user it retrieved from the database and a second object that has the same primary key. EF balks at that and throws an exception.
So the .X=15 approach is the correct one. You should update all relevant properties on the userToBeUpated from CUser and then save changes.
I try to add a new value to my database. UserPassword and RePassword must have the same value and a user with UserName must not already exist in the database.
public User NewUser(int HotelID, string UserName, string UserPassword, string RePassword, string FullName, string Email, bool Active, bool MasterUser)
{
User user = new User();
user.HotelID = HotelID;
user.UserName = UserName;
user.UserPassword = UserPassword;
user.FullName = FullName;
user.Email = Email;
user.IsActiveq = Active;
user.IsMaster = MasterUser;
var cekUser = (from c in _UserRepository.All()
where c.HotelID == HotelID
select c.UserName).ToList();
if (UserPassword == RePassword)
{
foreach (string cek in cekUser)
{
var x = cek;
if (UserName != x)
{
_UserRepository.Add(user);
}
}
}
_UserRepository.CommitChanges();
return user;
}
Every time I run my code a new line is added to the database, although a user with the supplied user name already exists in the database.
Why does this happen? Which part of my code is wrong?
I think your code should be something like this:
if (UserPassword == RePassword)
{
// Also I thinks you should finish whether user existed logic in database
// but for now, let's follow your original logic
var existedUsers = (from c in _UserRepository.All()
where c.HotelID == HotelID
select c.UserName).ToList();
if (!existedUsers.Any(u => u == UserName))
{
_UserRepository.Add(user);
_UserRepository.CommitChanges();
}
}
You have your logic wrong. If there is more than one user in a given hotel, your code will be adding more users for all users with names different from UserName.
bool found = false;
foreach(string cek in cekUser)
{
if ( UserName == cek)
{
found = true;
break;
}
}
if (!found)
_UserRepository.Add(user);
Just offering an alternate idea.
If you have access to the database, the best approach will be to make the Username field UNIQUE. That way, even if you get your code wrong, a duplicate insert will fail. Then you capture that fail gracefully in your Repository, and Bob's your uncle.
I am using MVC3-Viewmodel model first on my project.
When a user enters a value in my DDL and TextArea and then click on my form button it will basicly execute a ajax url.post to my POST action, right now my Post Action method creates and saves it. But what I want is some type of check, example:
step 1: If SelectQuestion has any answer
step 2: If answer exist do an update
step 3: if answer do not exist create a new and save it.
This is how my controller looks like now:
[HttpPost]
public JsonResult AnswerForm(int id, SelectedQuestionViewModel model)
{
bool result = false;
var goalCardQuestionAnswer = new GoalCardQuestionAnswer(); // Creates an instance of the entity that I want to fill with data
SelectedQuestion SelectedQ = answerNKIRepository.GetSelectedQuestionByID(model.QuestionID); // Retrieve SelectedQuestion from my repository with my QuestionID.
goalCardQuestionAnswer.SelectedQuestion = SelectedQ; // Filling my entity with SelectedQ
goalCardQuestionAnswer.SelectedQuestion.Id = model.QuestionID; // filling my foreign key with the QuestionID
goalCardQuestionAnswer.Comment = model.Comment; // Filling my entity attribute with data
goalCardQuestionAnswer.Grade = model.Grade; // Filling my entity attribute with data
answerNKIRepository.SaveQuestionAnswer(goalCardQuestionAnswer); // adding my object
answerNKIRepository.Save(); // saving
result = true;
return Json(result);
}
Comment and Grade are nullable aswell.
The entitys are associated like
[Question](1)------(*)[SelectedQuestion](1)-----(0..1)[GoalCardQuestionAnswer]
Any kind of help is appreciated.
Thanks in advance!
I achieved my question and the answer is following:
[HttpPost]
public JsonResult AnswerForm(int id, SelectedQuestionViewModel model)
{
SelectedQuestion SelectedQ = answerNKIRepository.GetSelectedQuestionByID(model.QuestionID);
if (SelectedQ.GoalCardQuestionAnswer == null)
{
var goalCardQuestionAnswer = new GoalCardQuestionAnswer();
goalCardQuestionAnswer.SelectedQuestion = SelectedQ;
goalCardQuestionAnswer.SelectedQuestion.Id = model.QuestionID;
goalCardQuestionAnswer.Comment = model.Comment;
goalCardQuestionAnswer.Grade = model.Grade;
this.answerNKIRepository.SaveQuestionAnswer(goalCardQuestionAnswer);
this.answerNKIRepository.Save();
const bool Result = true;
return this.Json(Result);
}
else
{
if (SelectedQ.GoalCardQuestionAnswer != null)
{
SelectedQ.GoalCardQuestionAnswer.Comment = model.Comment;
}
if (SelectedQ.GoalCardQuestionAnswer != null)
{
SelectedQ.GoalCardQuestionAnswer.Grade = model.Grade;
}
const bool Result = false;
return this.Json(Result);
}
}
Let's say I have this code:
class Score
{
public Update(int score)
{
update score but do not call (context.SaveChanges())
}
}
class Foo
{
public DoSomething(int update)
{
Score score = new Score();
score.Update(2);
SomeObj obj = (select object);
obj.Soo = 3;
context.SaveChanges();
}
}
Basically to make it work, I need to explicity provide SaveChanges in method Update. But when I have 4 such methods in row, and 34243 users want to update data, I don't think saving for each one in 4 trips would be a good idea.
Is there way in EF4.1 to delay database update the last moment, in provided example, Or I'm forced to explicity save for each method ?
EDIT:
For clarification. I tried to do not call SaveChanges in external method, and only one time where the changes mu be saved.
I will give an real example:
public class ScoreService : IScoreService
{
private JamiContext _ctx;
private IRepository<User> _usrRepo;
public ScoreService(IRepository<User> usrRepo)
{
_ctx = new JamiContext();
_usrRepo = usrRepo;
}
public void PostScore(int userId, GlobalSettings gs, string name)
{
User user = _ctx.UserSet.Where(x => x.Id == userId).FirstOrDefault();
if (name == "up")
{
user.Rating = user.Rating + gs.ScoreForLike;
}
else if (name == "down")
{
user.Rating = user.Rating - Math.Abs(gs.ScoreForDislike);
}
}
}
And Now:
public PostRating LikeDislike(User user, int postId, int userId, GlobalSettings set, string name)
{
PostRating model = new PostRating();
var post = (from p in _ctx.PostSet
where p.Id == postId
select p).FirstOrDefault();
if (name == "up")
{
post.Like = post.Like + 1;
model.Rating = post.Like - post.Dislike;
}
else if (name == "down")
{
post.Dislike = post.Dislike + 1;
model.Rating = post.Like - post.Dislike;
}
PostVote pv = new PostVote();
pv.PostId = post.Id;
pv.UserId = user.Id;
_ctx.PostVoteSet.Add(pv);
_scoreSrv.PostScore(userId, set, name);
_ctx.SaveChanges();
return model;
}
I this case user rating do not update, Until I call SaveChanges in PostScore
In your example it looks like PostScore and LikeDislike use different context instances. That is the source of your problem and there is no way to avoid calling multiple SaveChanges in that case. The whole operation is single unit of work and because of that it should use single context instance. Using multiple context instances in this case is wrong design.
Anyway even if you call single SaveChanges you will still have separate roundtrip to the database for each updated, inserted or deleted entity because EF doesn't support command batching.
The way to delay database update to the last moment is by not calling SaveChanges until the last moment.
You have complete control over this code, and if your code is calling SaveChanges after every update, then that needs changing.
This not really solves my entire problem, but at least I can use single instance of Context:
With Ninject:
Bind<JamiContext>().To<JamiContext>().InRequestScope();
And then constructor:
private JamiContext _ctx;
private IRepository<User> _usrRepo;
public ScoreService(IRepository<User> usrRepo, JamiContext ctx)
{
_ctx = ctx;
_usrRepo = usrRepo;
}