I've got a project I've inherited and I've recently just started working with RavenDb. I'm needing to save a document to one database that already has a connection with, but I need to save that document to a second RavenDb. Just wondering how I would go about that? Below is the method I would need to alter.
[HttpPost]
public ActionResult SaveContact(ContactInput input)
{
var id = getId();
var profile = RavenSession.Load<TechProfile>(id) ?? new TechProfile();
input.MapPropertiesToInstance(profile);
// check for existing user
if (RavenSession.Query<TechProfile>().Any(x => x.Email == profile.Email && x.Id != profile.Id))
{
return Json(new {error = "Profile already exists with that email address.", msg = "Error"});
}
RavenSession.Store(profile);
return Json(new {error = "", msg = "Success", id = profile.Id.Substring(profile.Id.LastIndexOf("/") + 1)});
}
You need to create a second session and point it toward the second database.
Entities aren't tied to a particular session in RavenDB, so you can do that.
Related
I have asp.net core web api with React client. I'm adding data through my user interface created in React. In my api, Db context is added as scoped service, and each time my request finishes and new one is started, all my data from previous request is lost.
This is how my Configure services looks like:
services.AddDbContext<TicketingContext>(o=>o.UseLazyLoadingProxies().UseSqlServer(connectionString));
Controller method for posting data looks like this:
[HttpPost("{id}/tickets")]
public IActionResult CreateNewTicket(string id,
[FromBody] TicketForCreationDto ticketForCreation)
{
if (ticketForCreation == null)
{
return BadRequest();
}
var ticketEntity = _mapper.Map<Ticket>(ticketForCreation);
_ticketRepository.AddNewTicket(ticketEntity);
_ticketRepository.AddTicketToClient(id, ticketEntity);
if (!_ticketRepository.Save())
{
throw new Exception("Creating ticket failed on save");
}
var ticketToReturn = _mapper.Map<TicketDto>(ticketEntity);
return CreatedAtRoute("GetTicket", new {id=id, ticketId = ticketToReturn.Id }, ticketToReturn);
}
and methods in repository like this:
AddNewTicket:
public void AddNewTicket(Ticket ticket)
{
if (ticket.Id == Guid.Empty)
{
ticket.Id = Guid.NewGuid();
}
var dispatcher = AssignTicketToDispatcher(ticket);
if (dispatcher == null)
{
throw new Exception("There are no dispatchers matching this ticket");
}
dispatcher.UserTickets.Add(new UserTicket()
{
IdentityUser = dispatcher,
Ticket = ticket,
UserId = dispatcher.Id,
TicketId = ticket.Id
});
_context.Tickets.Add(ticket);
}
AddTicketToClient:
public void AddTicketToClient(string id, Ticket ticket)
{
var client = _identityUserRepository.GetClient(id);
if (client == null)
{
client = _context.Users.Where(u => u.UserName == "username").FirstOrDefault();
}
client.UserTickets.Add(new UserTicket()
{
IdentityUser = client,
Ticket = ticket,
UserId = client.Id,
TicketId = ticket.Id
});
}
Save:
public bool Save()
{
return (_context.SaveChanges() >= 0);
}
I want to be able to store data gained through multiple requests.
Does anyone have idea how to do that?
Use the database as it's the best method you have for persisting your data.
So When you do a request - at the end of the request, after your latest data is saved - query for the data from previous requests that you need and return it.
e.g. retrieve the last 5 requests saved newest first (where id is example for your primary key field):
var latestSaved = _context.UserTickets.OrderByDescending(x => x.id).Take(5);
Or amend to return all relevant data for e.g. active user by passing a user id stored client side.
Pass through any params you need to request the relevant data.
Use joins / includes set up in your entities. Whatever you need to do - make use of your entity relationships to get what you need from you database. Why try and replicate what it already does? :)
This is truly one of the strangest issues I've run into.
I have a Web API which uses EF. I have an audit table which takes an ApplicationUser. I create the new object, add it to the collection and then call SaveChangesAsync(). The weird part is, I get "User name MyUserName is already taken." error.
using (var context = new ApplicationDbContext())
{
var user = context.Users.Single<ApplicationUser>(x => x.UserName == model.UserName);
var sid = context.SessionIds.FirstOrDefault(x => x.Id == model.SessionId);
var audit = new Audit
{
Data = model.Data,
User = user,
IpAddress = Helper.GetClientIp(Request),
Session = sid != null ? sid : ItsMyChance.Entities.Entities.SessionId.Create(scoreModel.UserName, scoreModel.GameId)
};
context.Audits.Add(audit);
await context.SaveChangesAsync();
}
Update
This code has been working for years. The difference is I upgrade from .NET 4.5 to .NET 4.61
Update 2
I also tried the following but still receive the same error
[ForeignKey("User")]
public string UserId { get; set; }
public ApplicationUser User { get; set; }
Update 3
Trying to track this issue down I call
var entries = context.ChangeTracker.Entries();
It returns several entries, 1 for each object, including User. User shows Added and another as Unchanged. I can't figure out how this is happening.
In addition, I added the following before making any changes but there's no effect.
context.Configuration.AutoDetectChangesEnabled = false;
Since You are adding the complete user object in Audit , so SaveChangesAsync will save a new Entry for Audit and User also and since a user with same username already exists that's why you are getting this error. What you should do is just assign just the UserId (Whatever is referral key in Audit table for User) in Audit object
var audit = new Audit
{
Data = model.Data,
UserId = user.Id,
IpAddress = Helper.GetClientIp(Request),
Session = sid != null ? sid : ItsMyChance.Entities.Entities.SessionId.Create(scoreModel.UserName, scoreModel.GameId)
};
I am using a web API with ASP.NET Core MVC, entityframework and angular as the front-end.
In my angular application I have Stepper component https://material.angular.io/components/stepper
In the first step I want to fill out my form and as soon as I click next I want to create the task and on the second form I want to update the settings for that newly created task. However, I need to get the PK of the newly created task to update the settings on my second form.
There is an api call to create a new task in the tTask table in sqlserver.
This is my API Post Method.
[ResponseType(typeof(CreatingTaskModel))]
public IHttpActionResult PosttTask(CreatingTaskModel CreatingTaskModel)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var newtTask= new tTask
{
TaskName = CreatingTaskModel.TaskName,
TaskDescription = CreatingTaskModel.TaskDescription,
EmailSubject = CreatingTaskModel.EmailSubject,
EmailBody = CreatingTaskModel.EmailBody,
FK_TaskTeam = CreatingTaskModel.tTaskTeam.pk_TaskTeam,
Enabled = CreatingTaskModel.Enabled ? 1:0,
};
db.tTasks.Add(newtTask);
db.SaveChanges();
var pk = new {id = CreatingTaskModel.PK_Task};
return Ok("Success");
}
This is the submit code in angular :
onSubmit()
{
if(this.taskForm.valid)
{
this.service.createTask(this.taskForm.value).subscribe((data) => {
debugger;
console.log(data)
})
}
}
I saw that return Ok() in my webapi returns a message and I was thinking of sorting the tTask table by decending order of after the db.SaveChanges();
and returning the last item that it find and sending it back in the Ok(pk) and then casting that into an integer on my client-side and using that to get the data to update it.
What is the correct way to do this? Should it be done in sql or on the webapi?
This is what I ended up doing:
var newObject = new
{
id = newtTask.PK_Task,
message = "Success"
};
return Ok(newObject);
and on angular I have this:
onSubmit(){
if(this.taskForm.valid) {
this.service.createTask(this.taskForm.value).subscribe((data) => {
if(data.message){
if(data.message == "Success"){
this.getRecipentData(data.id);
this.AdditionalRecipientForm.controls['FK_Task'].setValue(data.id);
this.pk_Task = data.id;
}
}
debugger;
console.log(data)
})
}
It just doesn't seem practical to do this, but it does the job. What do you guys think? Should I maybe instead of going to the serve twice maybe after it goes to the done filling out both forms submit them both? Like call create method in my API and then call my second API to update the data the was submitted in the second form. I am just looking for ideas or most common practice for these types of situations.
After you've added it to the database and called db.SaveChanges, the key will be assigned to the object. So, after db.SaveChanges, you should just be able to simply reference newtTask.Id.
So I assume you manually assign the id of the new task via PK_Task = CreatingTaskModel.PK_Task, and that it's indeed this id that gets saved to the Db. Therefore the id column should not be autoincrementing.
If that's true you can, as Louis said before, simply return your object or only the id if you're concerned about bandwidth.
You can do return new OkObjectResult(pk); or just use the shorthand: return Ok(pk);, which will also return an OkObjectResult with the pk object as payload.
I'm just getting into mvc 4 (and mvc in general) and am just wondering is this action code ok or should it be stripped down again?
[HttpPost]
public ActionResult Index(DashboardViewModel dbModel)
{
//retrieve latest resident order
var residentOrder = db.ResidentOrders.GetById(dbModel.ResidentOrderID);
if (residentOrder == null)
{
var order = db.Orders.GetById(dbModel.OrderID);
var user = db.Users.GetUserByUsername(User.Identity.Name);
residentOrder = new ResidentOrder()
{
CreatedDate=DateTime.Now,
LastUpdateDate = DateTime.Now,
Litres=0,
Customer = user
};
order.ResidentOrders.Add(residentOrder);
db.Commit();
}
//check to see if value has changed
if (!dbModel.ResidentLitresOrdered.Equals(residentOrder.Litres))
{
//get new ordered value
residentOrder.Litres = dbModel.ResidentLitresOrdered;
db.Commit();
//send an email just to notify in writing of the change.
SendOwnOrderQtyUpdateNotification();
}
return View(dbModel);
}
Basically if a resident order doesnt exist then we create one, this is the only place in the system where this would need to happen.
Should I still be stripping that code out into my repositories?
db is my IUnitOfWork btw
I would recommend that you create a "repository" to hide the details from the Controller action.
An "Upsert" method would allow this to be clearly and elegantly implemented hiding the details from the controller.
I'm developing a web app based on Orchard.
I'm coding a module that manages Staff Users, this users are ContentTypes(Staff_User) composed of UserPart and StaffUserPart (Custom part, defined in a migration) -> this part has a MediaPickerField.
This is the code in my controller to show the creation template of a staff users
public ActionResult CreateStaff() {
IContent staffUser = _contentManager.New("Staff_User");
var model = _contentManager.BuildEditor(staffUser);
return View((object)model);
}
Ok, I have a template in EditorTemplates/Staff.cshtml . The MediaPicker field is attached by the the BuildEditor function (as a shape).
This is the Post controller:
public ActionResult CreateStaffPost(FormCollection input) {
IContent staffUser = _contentManager.New("Staff_User");
//UserPart validation
if (String.IsNullOrEmpty(input["user.Email"]))
ModelState.AddModelError("Email", "The Email field is required.");
//Check if user already exits
var oldUser = _contentManager.Query("User").Where<UserPartRecord>(x => x.Email == input["user.Email"])
.List()
.FirstOrDefault();
if (oldUser != null)
ModelState.AddModelError("Email", "That email adress is already registered.");
if (!ModelState.IsValid) {
var model = _contentManager.UpdateEditor(staffUser, this);
return View(model);
}
StaffUserPart staff = staffUser.As<StaffUserPart>();
staff.FirstName = input["FirstName"];
staff.LastName = input["LastName"];
staff.Location = input["Location"];
staff.JobTitle = input["JobTitle"];
staff.Summary = input["Summary"];
staff.AreaOfExpertise = input["AreaOfExperience"];
staff.Category = input["Category"];
staff.Experience = input["Experience"];
//Media picker field values
var staffImageField = (MediaPickerField)staff.Fields.Single(x => x.Name == "Photo");
//TODO Fix image save during creation
staffImageField.Url = input["StaffUserPart.Photo.Url"];
staffImageField.AlternateText = input["StaffUserPart.Photo.AlternateText"];
staffImageField.Class = input["StaffUserPart.Photo.Class"];
staffImageField.Style = input["StaffUserPart.Photo.Style"];
staffImageField.Alignment = input["StaffUserPart.Photo.Alignment"];
staffImageField.Width = String.IsNullOrEmpty(input["StaffUserPart.Photo.Width"]) ? 0 : Convert.ToInt32(input["StaffUserPart.Photo.Width"]);
staffImageField.Height = String.IsNullOrEmpty(input["StaffUserPart.Photo.Height"]) ? 0 : Convert.ToInt32(input["StaffUserPart.Photo.Height"]);
UserPart userPart = staffUser.As<UserPart>();
userPart.UserName = input["user.Email"];
userPart.Email = input["user.Email"];
userPart.NormalizedUserName = input["user.Email"].ToLowerInvariant();
userPart.Record.HashAlgorithm = "SHA1";
userPart.RegistrationStatus = UserStatus.Approved;
userPart.EmailStatus = UserStatus.Approved;
//Set Password
_membershipService.SetPassword(userPart.As<UserPart>(), input["password"]);
//Create the StaffUser
_contentManager.Create(staffUser);
return RedirectToAction("Index");
}
Question
This works but the MediaPickerField doesn;t save the data. I use the debugger to see if the values from input["StaffUserPart.Photo"] and the values are there.
Any ideas?
It looks like you're doing more work than you need to. If you move your call to UpdateEditor, this method will do the work of putting posted values into your content. You'll need to make sure you're implementing IUpdater. Also, I added a dependency on ITransactionManager. I'm hoping this will help catch something not getting put in the right spot.
public ActionResult CreateStaffPost(FormCollection input) {
IContent staffUser = _contentManager.New("Staff_User");
//Create the StaffUser
_contentManager.Create(staffUser);
//UserPart validation
if (String.IsNullOrEmpty(input["user.Email"]))
ModelState.AddModelError("Email", "The Email field is required.");
//Check if user already exits
var oldUser = _contentManager.Query("User").Where<UserPartRecord>(x => x.Email == input["user.Email"])
.List()
.FirstOrDefault();
if (oldUser != null)
ModelState.AddModelError("Email", "That email adress is already registered.");
//This does all the work of hydrating your model
var model = _contentManager.UpdateEditor(staffUser, this);
if (!ModelState.IsValid) {
_transactionManager.Cancel();
return View(model);
}
//Set Password
_membershipService.SetPassword(userPart.As<UserPart>(), input["password"]);
return RedirectToAction("Index");
}