Asp.Net MVC 3 - Linq To Entities - PK with Null doesn't get inserted into the db (don't want null :)) - asp.net-mvc

I'm using the latest Asp.Net MVC version.
For some reason, when my POST (Action Create) in my controller gets hit.
I can't seem to be able to add it to the entityset.
What i have is,
1) My EntityModel (*.edmx file)
2) Controller which references the entity:
private db.DataContainer _db = new db.DataContainer();
3) My method (i'm using Guid as pk):
[HttpPost]
public ActionResult Create(Client client)
{
try
{
client.Id = Guid.NewGuid();
/* method 2
Client cl = new Client();
cl.Id = Guid.NewGuid();
cl.email = client.email;
cl.Adres = client.Adres;
cl.companyName = client.companyName;
cl.fax = client.fax;
cl.phone = client.phone;
*/
// client.Id = Guid.NewGuid();
_db.ClientSet.AddObject(client);
_db.SaveChanges();
return RedirectToAction("Index");
}
catch (Exception ex)
{
var ex_message = ex.Message;
var ex_data = ex.Data;
var ex_ix = ex.InnerException;
return View();
}
}
4) Following is my InnerException:
[System.Data.SqlClient.SqlException] = {"Cannot insert the value NULL into column 'Id', table 'lst.dbo.ClientSet'; column does not allow nulls. INSERT fails.\r\nThe statement has been terminated."}
Both doesn't seem to work :(

GUIDs are not supported as primary keys in the Entity Framework. You will need to modify your save method to generate a new GUID for your added objects http://msdn.microsoft.com/en-us/library/dd283139.aspx

It seems that changing my "saveCommand" has given my a temporarily solution:
I chaned:
_db.SaveChanges()
To
_db.SaveChanges(System.Data.Objects.SaveOptions.None);

Related

MVC Full Calendar Error [duplicate]

I am trying to do a simple JSON return but I am having issues I have the following below.
public JsonResult GetEventData()
{
var data = Event.Find(x => x.ID != 0);
return Json(data);
}
I get a HTTP 500 with the exception as shown in the title of this question. I also tried
var data = Event.All().ToList()
That gave the same problem.
Is this a bug or my implementation?
It seems that there are circular references in your object hierarchy which is not supported by the JSON serializer. Do you need all the columns? You could pick up only the properties you need in the view:
return Json(new
{
PropertyINeed1 = data.PropertyINeed1,
PropertyINeed2 = data.PropertyINeed2
});
This will make your JSON object lighter and easier to understand. If you have many properties, AutoMapper could be used to automatically map between DTO objects and View objects.
I had the same problem and solved by using Newtonsoft.Json;
var list = JsonConvert.SerializeObject(model,
Formatting.None,
new JsonSerializerSettings() {
ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
});
return Content(list, "application/json");
This actually happens because the complex objects are what makes the resulting json object fails.
And it fails because when the object is mapped it maps the children, which maps their parents, making a circular reference to occur. Json would take infinite time to serialize it, so it prevents the problem with the exception.
Entity Framework mapping also produces the same behavior, and the solution is to discard all unwanted properties.
Just expliciting the final answer, the whole code would be:
public JsonResult getJson()
{
DataContext db = new DataContext ();
return this.Json(
new {
Result = (from obj in db.Things select new {Id = obj.Id, Name = obj.Name})
}
, JsonRequestBehavior.AllowGet
);
}
It could also be the following in case you don't want the objects inside a Result property:
public JsonResult getJson()
{
DataContext db = new DataContext ();
return this.Json(
(from obj in db.Things select new {Id = obj.Id, Name = obj.Name})
, JsonRequestBehavior.AllowGet
);
}
To sum things up, there are 4 solutions to this:
Solution 1: turn off ProxyCreation for the DBContext and restore it in the end.
private DBEntities db = new DBEntities();//dbcontext
public ActionResult Index()
{
bool proxyCreation = db.Configuration.ProxyCreationEnabled;
try
{
//set ProxyCreation to false
db.Configuration.ProxyCreationEnabled = false;
var data = db.Products.ToList();
return Json(data, JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
Response.StatusCode = (int)HttpStatusCode.BadRequest;
return Json(ex.Message);
}
finally
{
//restore ProxyCreation to its original state
db.Configuration.ProxyCreationEnabled = proxyCreation;
}
}
Solution 2: Using JsonConvert by Setting ReferenceLoopHandling to ignore on the serializer settings.
//using using Newtonsoft.Json;
private DBEntities db = new DBEntities();//dbcontext
public ActionResult Index()
{
try
{
var data = db.Products.ToList();
JsonSerializerSettings jss = new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore };
var result = JsonConvert.SerializeObject(data, Formatting.Indented, jss);
return Json(result, JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
Response.StatusCode = (int)HttpStatusCode.BadRequest;
return Json(ex.Message);
}
}
Following two solutions are the same, but using a model is better because it's strong typed.
Solution 3: return a Model which includes the needed properties only.
private DBEntities db = new DBEntities();//dbcontext
public class ProductModel
{
public int Product_ID { get; set;}
public string Product_Name { get; set;}
public double Product_Price { get; set;}
}
public ActionResult Index()
{
try
{
var data = db.Products.Select(p => new ProductModel
{
Product_ID = p.Product_ID,
Product_Name = p.Product_Name,
Product_Price = p.Product_Price
}).ToList();
return Json(data, JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
Response.StatusCode = (int)HttpStatusCode.BadRequest;
return Json(ex.Message);
}
}
Solution 4: return a new dynamic object which includes the needed properties only.
private DBEntities db = new DBEntities();//dbcontext
public ActionResult Index()
{
try
{
var data = db.Products.Select(p => new
{
Product_ID = p.Product_ID,
Product_Name = p.Product_Name,
Product_Price = p.Product_Price
}).ToList();
return Json(data, JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
Response.StatusCode = (int)HttpStatusCode.BadRequest;
return Json(ex.Message);
}
}
JSON, like xml and various other formats, is a tree-based serialization format. It won't love you if you have circular references in your objects, as the "tree" would be:
root B => child A => parent B => child A => parent B => ...
There are often ways of disabling navigation along a certain path; for example, with XmlSerializer you might mark the parent property as XmlIgnore. I don't know if this is possible with the json serializer in question, nor whether DatabaseColumn has suitable markers (very unlikely, as it would need to reference every serialization API)
add [JsonIgnore] to virtuals properties in your model.
Using Newtonsoft.Json: In your Global.asax Application_Start method add this line:
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
Its because of the new DbContext T4 template that is used for generating the EntityFramework entities. In order to be able to perform the change tracking, this templates uses the Proxy pattern, by wrapping your nice POCOs with them. This then causes the issues when serializing with the JavaScriptSerializer.
So then the 2 solutions are:
Either you just serialize and return the properties you need on the client
You may switch off the automatic generation of proxies by setting it on the context's configuration
context.Configuration.ProxyCreationEnabled = false;
Very well explained in the below article.
http://juristr.com/blog/2011/08/javascriptserializer-circular-reference/
Provided answers are good, but I think they can be improved by adding an "architectural" perspective.
Investigation
MVC's Controller.Json function is doing the job, but it is very poor at providing a relevant error in this case. By using Newtonsoft.Json.JsonConvert.SerializeObject, the error specifies exactly what is the property that is triggering the circular reference. This is particularly useful when serializing more complex object hierarchies.
Proper architecture
One should never try to serialize data models (e.g. EF models), as ORM's navigation properties is the road to perdition when it comes to serialization. Data flow should be the following:
Database -> data models -> service models -> JSON string
Service models can be obtained from data models using auto mappers (e.g. Automapper). While this does not guarantee lack of circular references, proper design should do it: service models should contain exactly what the service consumer requires (i.e. the properties).
In those rare cases, when the client requests a hierarchy involving the same object type on different levels, the service can create a linear structure with parent->child relationship (using just identifiers, not references).
Modern applications tend to avoid loading complex data structures at once and service models should be slim. E.g.:
access an event - only header data (identifier, name, date etc.) is loaded -> service model (JSON) containing only header data
managed attendees list - access a popup and lazy load the list -> service model (JSON) containing only the list of attendees
Avoid converting the table object directly. If relations are set between other tables, it might throw this error.
Rather, you can create a model class, assign values to the class object and then serialize it.
I'm Using the fix, Because Using Knockout in MVC5 views.
On action
return Json(ModelHelper.GetJsonModel<Core_User>(viewModel));
function
public static TEntity GetJsonModel<TEntity>(TEntity Entity) where TEntity : class
{
TEntity Entity_ = Activator.CreateInstance(typeof(TEntity)) as TEntity;
foreach (var item in Entity.GetType().GetProperties())
{
if (item.PropertyType.ToString().IndexOf("Generic.ICollection") == -1 && item.PropertyType.ToString().IndexOf("SaymenCore.DAL.") == -1)
item.SetValue(Entity_, Entity.GetPropValue(item.Name));
}
return Entity_;
}
You can notice the properties that cause the circular reference. Then you can do something like:
private Object DeCircular(Object object)
{
// Set properties that cause the circular reference to null
return object
}
//first: Create a class as your view model
public class EventViewModel
{
public int Id{get;set}
public string Property1{get;set;}
public string Property2{get;set;}
}
//then from your method
[HttpGet]
public async Task<ActionResult> GetEvent()
{
var events = await db.Event.Find(x => x.ID != 0);
List<EventViewModel> model = events.Select(event => new EventViewModel(){
Id = event.Id,
Property1 = event.Property1,
Property1 = event.Property2
}).ToList();
return Json(new{ data = model }, JsonRequestBehavior.AllowGet);
}
An easier alternative to solve this problem is to return an string, and format that string to json with JavaScriptSerializer.
public string GetEntityInJson()
{
JavaScriptSerializer j = new JavaScriptSerializer();
var entityList = dataContext.Entitites.Select(x => new { ID = x.ID, AnotherAttribute = x.AnotherAttribute });
return j.Serialize(entityList );
}
It is important the "Select" part, which choose the properties you want in your view. Some object have a reference for the parent. If you do not choose the attributes, the circular reference may appear, if you just take the tables as a whole.
Do not do this:
public string GetEntityInJson()
{
JavaScriptSerializer j = new JavaScriptSerializer();
var entityList = dataContext.Entitites.toList();
return j.Serialize(entityList );
}
Do this instead if you don't want the whole table:
public string GetEntityInJson()
{
JavaScriptSerializer j = new JavaScriptSerializer();
var entityList = dataContext.Entitites.Select(x => new { ID = x.ID, AnotherAttribute = x.AnotherAttribute });
return j.Serialize(entityList );
}
This helps render a view with less data, just with the attributes you need, and makes your web run faster.

Not able to update the data using entity framework

I have following code. in that i am trying to update my data. but i am getting error message:
An exception of type 'System.InvalidOperationException' occurred in EntityFramework.dll but was not handled in user code
Additional information: An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key.
Here is my code:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include="CompanyId,Address,EstbalishYear,Email,IsActive")] CompanyMaster companymaster)
{
if (companymaster.CompanyId == 0)
{
return View(companymaster);
}
CompanyMaster company = db.CompanyMasters.SingleOrDefault(x => x.CompanyId == companymaster.CompanyId);
companymaster.Name = company.Name;
companymaster.InsertedBy = company.InsertedBy;
companymaster.InsertedTime = company.InsertedTime;
companymaster.UpdatedBy = 1;
companymaster.UpdatedTime = DateTime.Now;
ModelState.Remove("Name");
if (ModelState.IsValid)
{
db.Entry(companymaster).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(companymaster);
}
Please explain me how can I fix this error message?
This is because you are working with two object instances of a company master, which in reality is a single entity, with the same ID.
One (companyMaster) comes as an argument to the Edit method, via binding.
The other one (company) you are selecting from the database through db.CompanyMasters by ID
What you can do is
Select company by ID, as you do now
Set company properties from companyMaster object (vice-versa, not like you do now)
Save the company object
Please find the sample code below.
Please also note that the best practice is not to use your persistence entity model in UI layer, but rather define a DTO with a minimum set of required fields, and then map it to your entity either manually or using AutoMapper.
[HttpPost] [ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include="CompanyId,Address,EstbalishYear,Email,IsActive")] CompanyMaster companymaster)
{
if (companymaster.CompanyId == 0)
{
return View(companymaster);
}
CompanyMaster company = db.CompanyMasters.SingleOrDefault(x => x.CompanyId == companymaster.CompanyId);
company.Address = companymaster.Address;
company.EstbalishYear= companymaster.EstbalishYear;
company.Email = companymaster.Email;
company.IsActive= companymaster.IsActive;
company.UpdatedBy = 1;
company.UpdatedTime = DateTime.Now;
ModelState.Remove("Name");
if (ModelState.IsValid)
{
db.SaveChanges();
return RedirectToAction("Index");
}
return View(companymaster);
}

Getting data from two tables

I have 2 tables tbl_computer and tbl_computerperipheral
I need a editor view which consists of data from both tables.
How Can I get 2 tables in a single view so that I can insert data into 2 tables at once.
Thanx
For your Better Reference just have a look to ::
How to Combine two models into a single model and pass it to view using asp.net MVC razor
and then on Form submit on server side (i.e. into controller's action) save the data coming from view in the form like::
public ActionResult Save(CommonViewModel common)
{
var FirstModel = new FirstModel();
FirstModel = common.FirstModel;
db.Entry(FirstModel).State = EntityState.Added;
var SecondModel = new SecondModel();
SecondModel = common.SecondModel;
db.Entry(SecondModel).State = EntityState.Added;
db.SaveChanges();
}
May be this answer will be helpful to get answer of your Query.
[HttpPost]
public ActionResult Edit(CompPeripheral cp, int c_id,int em_id,int asset_id)
{
if (ModelState.IsValid)
{
cp.Compconfig.c_id = c_id;
cp.Compconfig.em_id = em_id;
cp.Compconfig.asset_id = asset_id;
db.tbl_compconfig.Add(cp.Compconfig);
db.SaveChanges();
var id = db.tbl_compconfig.Max(a => a.comp_id);
cp.Comperipheral.comp_id = id;
//saving Comp Peripheral in database
db.tbl_comperipheral.Add(cp.Comperipheral);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.asset_id = new SelectList(db.tbl_assetm, "asset_id", "asset_name", cp.Compconfig.asset_id);
ViewBag.em_id = new SelectList(db.tbl_employee, "em_id", "em_fullname", cp.Compconfig.em_id);
ViewBag.c_id = new SelectList(db.tbl_client, "c_id", "c_name", cp.Compconfig.c_id);
return View(cp);
}

Store update, insert, or delete statement affected

Im learning MVC 4. I have created a database first project using EF5. In my edit view I want to add a product number to a customer. When I hit save I get the message below. I think it is because product number is null in the product table, hence it cannot update. Can I get around this? I have added my edit control
public ActionResult Edit(int id = 0)
{
UserProfile userprofile = db.UserProfiles.Find(id);
if (userprofile == null)
{
return HttpNotFound();
}
//ViewBag.userId = new SelectList(db.Devices, "DeviceID", "DeviceIMEI", userprofile.UserId);THIS CREATES A NEW ENTRY IN USERPROFILE TABLE
ViewBag.Device_DeviceID = new SelectList(db.Devices, "DeviceID", "DeviceIMEI", userprofile.Device);
ViewBag.ShippingDetails_ShippingDetailsID = new SelectList(db.ShippingDetails, "ShippingDetailsID", "Address1", userprofile.ShippingDetails_ShippingDetailsID);
return View(userprofile);
}
//
// POST: /User/Edit/5
[HttpPost]
public ActionResult Edit(UserProfile userprofile)
{
if (ModelState.IsValid)
{
db.Entry(userprofile).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
//ViewBag.userId = new SelectList(db.Devices, "DeviceID", "DeviceIMEI", userprofile.UserId);
ViewBag.Device_DeviceID = new SelectList(db.Devices, "DeviceID", "DeviceIMEI", userprofile.Device);
ViewBag.ShippingDetails_ShippingDetailsID = new SelectList(db.ShippingDetails, "ShippingDetailsID", "Address1", userprofile.ShippingDetails_ShippingDetailsID);
return View(userprofile);
}
"Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries"
It looks like you dont pass Id of UserProfile from
view to controller.
You should add
#Html.HiddenFor(model => model.Id)
to your form in view
You're posting a view model, which is disconnected from your entity framework, and trying to tell the EF that it has changed -- which it doesn't know about. Try something like this instead,
var obj = yourContext.UserProfiles.Single(q=>q.Id==userProfile.Id);
obj = userprofile; // ... Map userprofile to the tracked object, obj
yourContext.SaveChanges();
Try this:
if (ModelState.IsValid)
{
db.UserProfiles.Attach(userProfile);
db.SaveChanges();
return RedirectToAction("Index");
}

MVC Entity Framework - Inserting Data - A dependent property in a ReferentialConstraint is mapped to a store-generated column

I need help with trying to insert a record using MVC and Entity Framework. I have a dynamically created form which can contain many questions. When Editing, I want to delete the existing answers (which it does successfully) and insert new answers.
I am getting the following error:
Cannot insert explicit value for identity column in table 'tblModeratorReportAnswers' when IDENTITY_INSERT is set to OFF.
If I add the following line in my DbContext class
modelBuilder.Entity<QuestionAnswer>().Property(p => p.AnswerID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); I get this error:
A dependent property in a ReferentialConstraint is mapped to a store-generated column. Column: 'AnswerID'.
Here's my code that is doing the update
//
// POST: /Home/Edit/1
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(FormCollection formCollection, int moderatorReportId)
{
ModeratorReport reportToEdit = repository.GetModeratorReportById(moderatorReportId);
List<QuestionAnswer> originalReportAnswers = repository.GetAllModeratorReportAnswers(moderatorReportId).ToList();
foreach (QuestionAnswer answer in originalReportAnswers) {
repository.DeleteAnswer(answer);
}
repository.Save();
int sectionID;
int questionID;
foreach (string key in formCollection.AllKeys)
{
var value = formCollection[key.ToString()];
Match m = Regex.Match(key, "section(\\d+)_question(\\d+)");
if (m.Success) {
QuestionAnswer newAnswer = new QuestionAnswer();
sectionID = Convert.ToInt16(m.Groups[1].Value.ToString());
questionID = Convert.ToInt16(m.Groups[2].Value.ToString());
newAnswer.ModeratorReportID = moderatorReportId;
newAnswer.QuestionID = questionID;
newAnswer.Answer = value;
repository.AddAnswer(newAnswer);
}
}
repository.Save();
reportToEdit.Status = "SUBJECTOFFICER SAVED";
AuditItem auditItem = new AuditItem();
auditItem.ModeratorReportID = moderatorReportId;
auditItem.Status = "SUBJECTOFFICER SAVED";
auditItem.AuditDate = DateTime.Now;
auditItem.Description = "The Moderator report ID: " + moderatorReportId + " was saved.";
auditItem.UserID = User.Identity.Name;
db.Audit.Add(auditItem);
repository.Save();
return RedirectToAction("Details", new { id = moderatorReportId });
}
...and in my repository
//
// Persistance
public void Save()
{
db.SaveChanges();
}
public void AddAnswer(QuestionAnswer answer)
{
db.Answers.Add(answer);
Save();
}
public void DeleteAnswer(QuestionAnswer answer)
{
db.Answers.Attach(answer);
db.Answers.Remove(answer);
}
I have also checked all my Primary Keys, Foreign Keys and they are all ok. The Primary Keys are all set to 'Is Identity'.
I've been trying to sort this problem out all day. I have no idea what to do to resolve it. If anyone can give my any advice, it'd be much appreciated.
Maybe it's my inexperience with ASP.NET MVC and Entity Framework, but I have now resolved this issue by changing the logic of that I update the report.
Instead of deleting the answers and reinserting them. I now retrieve the answers and change Answer property to be the new answer. Then just use db.SaveChanges().
//
// POST: /Home/Edit/1
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(FormCollection formCollection, int moderatorReportId)
{
ModeratorReport reportToEdit = repository.GetModeratorReportById(moderatorReportId);
List<QuestionAnswer> originalReportAnswers = repository.GetAllModeratorReportAnswers(moderatorReportId).ToList();
int sectionID;
int questionID;
foreach (string key in formCollection.AllKeys)
{
var value = formCollection[key.ToString()];
Match m = Regex.Match(key, "section(\\d+)_question(\\d+)");
if (m.Success) {
QuestionAnswer newAnswer = new QuestionAnswer();
sectionID = Convert.ToInt16(m.Groups[1].Value.ToString());
questionID = Convert.ToInt16(m.Groups[2].Value.ToString());
foreach(QuestionAnswer answerToEdit in originalReportAnswers) {
if (answerToEdit.QuestionID == questionID)
{
answerToEdit.Answer = value;
}
}
}
}
repository.Save();
reportToEdit.Status = "SAVED";
AuditItem auditItem = new AuditItem();
auditItem.ModeratorReportID = moderatorReportId;
auditItem.Status = "SAVED";
auditItem.AuditDate = DateTime.Now;
auditItem.Description = "The Moderator report ID was saved.";
auditItem.UserID = User.Identity.Name;
db.Audit.Add(auditItem);
repository.Save();
return RedirectToAction("Details", new { id = moderatorReportId });
}
Cannot insert explicit value for identity column in table
'tblModeratorReportAnswers' when IDENTITY_INSERT is set to OFF.
This error says that you are explicitly inserting value into autogenerated column (identity column).
A dependent property in a ReferentialConstraint is mapped to a
store-generated column. Column: 'AnswerID'.
This error says that there is some incorrectly configured relation where autogenerated AnswerID is considered as FK - that is not supported. Identity and Computed properties must not be FKs.

Resources