I have multiple Data Models created with the Entity framework (EDMX), and want to load based on specific conditions (similar to factory model) like so:
demoEntity obj
if(condtion1)
{
obj= new firstmodel();
}
else if
{
obj= new secondmodel();
}
Is there any way this can be done?
Related
I am trying to add a new record in an MVC controller method using Entity framework.
When i just used "InsertOrUpdate" the audittype got duplicated. Based on the answer from Entity Framework adding record with a related object i hoped to fix it pretty qiock. This is the code I have right now:
Controller:
if (ModelState.IsValid)
{
Audit newAudit = Factory.GetNew();
newAudit.Name = model.Name;
newAudit.Deadline = model.Deadline;
newAudit.AuditType = auditTypeRepository.Find(model.SelectedAuditTypeId);
Repository.InsertOrUpdate(newAudit);
Repository.Save();
return RedirectToAction(MVC.Audits.Details(newAudit.Id));
}
Repository:
public override void InsertOrUpdate(Qdsa.WebApplications.AuditMaster.Data.Audit model)
{
if (model.Id == default(int))
{
// New entity
context.Audits.Add(model);
}
else
{
// Existing entity
model.ModifiedOn = DateTime.Now;
context.Entry(model).State = EntityState.Modified;
}
//If I leave out the code below the AuditType will be duplicated
if (model.AuditType != null)
{
context.Entry<AuditType>(model.AuditType).State = EntityState.Unchanged;
}
}
public virtual void Save()
{
context.SaveChanges();
}
So i thought I fixed the problem. However, AuditType has Child objects too. And now these childobjects get duplicated.
What is the right way to add entities with child objects which already exists?
Because the AuditType is required I can't save it without first and then update it. any suggestions?
UPDATE:
Both the AuditRepostory and the AuditTypeRepository inherit from BaseRepository which has the context as:
protected DBContext context = new DBContext ();
public virtual T Find(int id)
{
return All.SingleOrDefault(s => s.Id == id);
}
I can imagine two reasons for the problem:
Either auditTypeRepository.Find performs a no tracking query (with .AsNoTracking())
Or you are using a context instance per repository, so that Repository and auditTypeRepository are working with two different contexts which will indeed result in a duplication of the AuditType because you don't attach it to the the context that corresponds with Repository (except in the line with your comment).
If the latter is the case you should rethink your design and inject a single context instance into all repositories instead of creating it inside of the repositories.
I think the problem is from here:
newAudit.AuditType = auditTypeRepository.Find(model.SelectedAuditTypeId);
Change that like this:
newAudit.AuditTypeId = model.SelectedAuditTypeId;
I have many to many relationship some tables. I am using entity framework.
Reservations >> ApartsToReservations << Aparts
ApartsToReservations include ReservationID and ApartID.
and my delete action below:
public ActionResult DeleteReservation(string resultId)
{
var result = Convert.ToInt32(resultId.Trim());
//just I have reservationID
return View();
}
How can delete reservation?
How can delete reservation?
For example:
[HttpPost] // <- should be a POST action because it's modifying data
public ActionResult DeleteReservation(string resultId)
{
var result = Convert.ToInt32(resultId.Trim());
//just I have reservationID
using (var context = new MyContext())
{
var reservation = new Reservation { ReservationID = result };
context.Reservations.Attach(reservation);
context.Reservations.Remove(reservation);
context.SaveChanges();
}
// ... redirect to Index or something, for example:
// return RedirectToAction("Index");
}
If you already have a context instance as a member of your controller class use this instead of creating a new one in the using block.
The code will also delete the related records in the ApartsToReservations link table because by default the relationships to this table are configured with cascading delete.
I'm not quite sure if this is what you are looking for because it actually doesn't matter if Reservation is involved in the many-to-many relationship you mentioned. It is just the (or one) standard way to delete an entity with DbContext.
If you are looking for something different please try to clarify your question or ask a new one which is clearer.
I'm looking at the single-page web application for MVC4 from VS templates (from here http://www.asp.net/single-page-application) and it looks like the PUT action for ToDoLists is creating a new ToDoList - why is this? The code from the DTO class definition:
public TodoList ToEntity()
{
TodoList todo = new TodoList
{
Title = Title,
TodoListId = TodoListId,
UserId = UserId,
Todos = new List<TodoItem>()
};
foreach (TodoItemDto item in Todos)
{
todo.Todos.Add(item.ToEntity());
}
return todo;
}
From the controller:
public HttpResponseMessage PutTodoList(int id, TodoListDto todoListDto)
{
TodoList todoList = todoListDto.ToEntity();
db.Entry(todoList).State = EntityState.Modified;
db.SaveChanges();
return Request.CreateResponse(HttpStatusCode.OK);
}
So to update a record, we create a new one? I'm a little confused about how this is working - any clarification would be awesome.
In this example, the controller is converting the TodoListDto object into a TodoList object, which is the database object type. Since the DTO object is coming back from the web page, it has to be changed into the appropriate type so that Entity Framework can attach it to the DbSet and save changes.
ToEntity doesn't actually create a new record in the database, it creates a new TodoList instance which then gets attached, as modified to the database.
I am trying to reuse the same form for adding and editing employee information. I am using knockout js and on my view I make the knockout model:
var koModel = new EmployeeModel(div);
and if I want to populate the fields from the server I want to do something like this:
var koModel = new EmployeeModel(unserializedModelFromController, div);
I was wondering what is the best way to distinguish if the request is for a new employee or if it is to edit an existing employee.
If you turn your parameters around you can write a single constructor function.
var EmployeeModel = function(div, model) {
if (model) {
// Existing model has been passed, it's an edit request
} else {
// No model has been passed, it's a new request
}
}
This can be called like:
new EmployeeModel(div);
or
new EmployeeModel(div, model);
You can send a parameter with a default value to the view.
If you are editing an employee, you can send the value of id, you're creating not send.
The function that receives a request to store or edit could have a default value.
public void SaveOrEditEmployee(int id=0, ...) //id=0 is a default value
{
if(id==0)
{
//SaveEmployee
}else
{
//EditEmployee
Employee empl = (x => employee.id == id);
...
}
}
Or you can do likewise, receive full model and assess whether the property 'id' already exists in your database
I am making an MVC4 web application using Entity Framework 5 (Database-first with generated POCOs) for data access.
In the app, the user goes through several screens, creating or editing a document (called a 'case study'). When they arrive at the final screen, their document exists as a CaseStudy POCO in memory, and everything is great until it is time to save this structure to the database.
To store the document, I have defined several database tables, which in turn map to EF POCOs used by the business layer, which is then consumed by the MVC controllers. As such, short-lived DbContexts are used to retrieve POCOs and store them in session between requests.
As a result, the save screen must save the contents of this POCO that has navigational properties to existing table data (Category, Layout, and Sections tables), and also added or updated data (CaseStudySections and the CaseStudy itself). So all of the POCOs are either new, or the context used to retrieve them has long been disposed. In other words, they are all 'detached'.
What is unusual about this post is that I already have a working solution in hand. The problem is that it is bulky, brittle, and inelegant. I am posting the code below. Note the iteration through sub-collections, the explicit adds and attaches, having to get an entry object and mark individual properties as modified just so they will be updated, and the awful song and dance at the end to get the AdditionalMaterials collection synced up. If this is what is required to deal with detached POCOs in EF5 I will be disappointed.
Am I missing something here? Is this consistent with best practices? Is there a more graceful and/or concise way to attach a structure of POCOs and insert/update?
The code to save a case study:
public void SaveCaseStudy(CaseStudy caseStudy)
{
foreach (var s in caseStudy.CaseStudySections)
{
this.Entities.Sections.Attach(s.Section);
if (s.CreatedByRefId == default(Guid))
{
s.CreatedByRefId = this.UserRefId;
s.CreatedTime = DateTime.Now;
this.Entities.CaseStudySections.Add(s);
}
else
{
this.Entities.CaseStudySections.Attach(s);
var entry = this.Entities.Entry(s);
entry.Property(e => e.TextData).IsModified = true;
entry.Property(e => e.BinaryData).IsModified = true;
}
s.LastModifiedByRefId = this.UserRefId;
s.LastModifiedTime = DateTime.Now;
}
foreach (var m in caseStudy.AdditionalMaterials)
{
if (m.CreatedByRefId == default(Guid))
{
m.CreatedByRefId = this.UserRefId;
m.CreatedTime = DateTime.Now;
this.Entities.AdditionalMaterials.Add(m);
}
else
{
this.Entities.AdditionalMaterials.Attach(m);
}
m.LastModifiedByRefId = this.UserRefId;
m.LastModifiedByTime = DateTime.Now;
}
this.Entities.Layouts.Attach(caseStudy.Layout);
this.Entities.Categories.Attach(caseStudy.Category);
if (caseStudy.CreatedByRefId != default(Guid))
{
this.Entities.CaseStudies.Attach(caseStudy);
var entry = this.Entities.Entry(caseStudy);
entry.Property(e => e.CaseStudyName).IsModified = true;
entry.Property(e => e.CaseStudyTitle).IsModified = true;
}
else
{
this.Entities.CaseStudies.Add(caseStudy);
caseStudy.CreatedByRefId = this.UserRefId;
caseStudy.CreatedTime = DateTime.Now;
}
caseStudy.LastModifiedByRefId = this.UserRefId;
caseStudy.LastModifiedTime = DateTime.Now;
if (caseStudy.CaseStudyStatus != (int)CaseStudyStatus.Personalized)
{
caseStudy.CaseStudyStatus = (int)CaseStudyStatus.PendingApproval;
}
caseStudy.ApprovedByRefId = null;
caseStudy.ApprovedTime = null;
this.Entities.SaveChanges();
var existingAdditionalMaterialRefIds = caseStudy.AdditionalMaterials
.Select(m => m.AdditionalMaterialRefId)
.ToArray();
var additionalMaterialsToRemove = this.Entities.AdditionalMaterials
.Where(m =>
m.CaseStudyRefId == caseStudy.CaseStudyRefId &&
!existingAdditionalMaterialRefIds.Contains(m.AdditionalMaterialRefId))
.ToArray();
foreach (var additionalMaterialToRemove in additionalMaterialsToRemove)
{
this.Entities.AdditionalMaterials.Remove(additionalMaterialToRemove);
}
this.Entities.SaveChanges();
}
In general it is what you have to do. You must tell EF about each change you want to perform when attaching detached object graph. I don't say that your code cannot be simplified but you will still have to deal with every entity and setting its state if you want it to be added or modified.
Here is little bit older but still valid answer about the topic - in short nothing has changes since I wrote it, only new DbContext API was created which still sits on top of the old API. The best description of this topic I have seen so far is in book Programming Entity Framework: DbContext.
How about just doing:
db.CaseStudies.Attach(caseStudy);
db.Entry(caseStudy).State = EntityState.Modified;
db.SaveChange();
That will save all changes in your model to the db.