Updating Foreign Key Table in EF4.1 MVC3. Object is null on POST - entity-framework

When i use foreign keys in the entity framework the foreign key object is null when i do a POST. I am using MVC3 and EF 4.1. I have two tables, Product and Product Details. I am exposing them using the HTML helpers in a Razor view. When the GET happens, the product details are shown. But when i do a form Submit and post to the server, the Product Details collection is null. I lose all my changes.
Any ideas what i am doing wrong?
Thanks for your help!
The Code (i shortened it because it is fairly lengthy):
Database:
Table Product
{
int Id
varchar Name
}
Table ProductDetails
{
int id,
int ProductId, <- foreign key SQL 2008 to Product Table
varchar Details
}
View:
#model WebSite.Models.Product
#{
ViewBag.Title = "MyLifeSaverStoreInfo";
}
#Html.TextBoxFor(m => m.Product.Name)
#Html.TextBoxFor(m => m.Product.ProductDetails.FirstOrDefault().Description)
Controller:
public ActionResult EditProduct(int productId)
{
var Product = _productRepository.GetProduct(productId);
return View(product);
}
[HttpPost]
public ActionResult EditProduct(Product model)
{
string name = model.Name; <- this update comes through
string description = model.ProductDetails.FirstorDefault().Description;
}
Thanks

Got it!
Instead of creating the "Product" entity on the POST EditProduct method, i use a Form Collection and then set each product detail according to that form collection and then save. I don't understand why it doesn't work the first way. I am manually updating the foreign reference. Maybe i am missing something?
[HttpPost]
public ActionResult EditProduct(int id, FormCollection formCollection)
{
var model = new MyLSstoreInfoViewModel{
StoreCurrent = _profileRepository.GetProduct(Id)
};
var productDetails = model.Product.ProductDetails.Where(p => p.productId == id).Single();
productDetaisl.Details = formCollection["details"];
if (TryUpdateModel(model.StoreCurrent))
{
_profileRepository.Save();
}
}

It's a bit late, but maybe useful for someone in the future:
If you pass the primary key of the referenced child as a hidden input in the view, it will correctly resolve the child model in the action.

Related

Entity framework with linq in asp.net mvc 5

I am using linq query to group by element through one table field, guid.
The problem is that I do not know how to retrieve the object on the view.
Here is my code:
public ActionResult Index2()
{
List<Imageupload> lists = db.Imageuploads.ToList();
var a = lists.GroupBy(g => g.guid);
return View(a);
}
Imageupload is a modal class and Imageuploads is a table in the database.
How can I accomplish that?
Try this:
var groupedList = db.Imageuploads
.GroupBy(u => u.guid)
.Select(g=> g.ToList())
.ToList();
Hope this helps

How to return identity value from Web API when posting to the database

I have two tables in my database that I am filling via Web API:
Orders
________
OrderID
OrderDate
OrderStatusID
and
OrderItems
___________
OrderID
ItemID
ItemNote
ItemSortOrder
and below is the method from my controller that I use to post Order to the database which works fine, I unit tested it previously.
[ResponseType(typeof(myClass.Order))]
[HttpPost]
public IHttpActionResult PostNewOrder(myClass.Order ord1)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
using (MyContext ctx = new MyContext())
{
ctx.Orders.Add(ord1);
ctx.SaveChanges();
return CreatedAtRoute("DefaultApi", new { id = ord1.OrderID }, ord1);
}
}
My question is - how can I return the OrderID of the newly inserted order from the database? OrderID field is an identity field in the database
No need to add any new code.
As soon as you call ctx.SaveChanges(); the object ord1 will then have the new id in the property OrderID.
You can do that by getting the Database values:
var dbObject = ctx.Entry(ord1).GetDatabaseValues();
return CreatedAtRoute("DefaultApi", new { id = dbObject["OrderID"] }, ord1);
ord1.OrderID will have the correct order id but you have to make sure that Entity Framework is mapped so that it knows the database will generate the value for the id. If you do that then the id is read back when you create your new order (or any entity that is added with an id column with that same mapping configuration applied).
You can map this on the id using either fluent mapping or an attribute. Here is the syntax for fluent:
modelBuilder.Entity<Order>()
.Property(x => x.OrderID)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
And for attributes
[DatabaseGenerated(DatabaseGenerationOption.Identity)]
public int OrderID { get; set; }
If you are using the designer (.EDMX file) for mapping see the the image below as an example of how you can set the store generation pattern.
Image was copied from a previous SO answer. https://stackoverflow.com/a/6306817/1260204
Note - you should pick one or the other, not both.
I'm guessing on Entity Framework based on the name used in the context.

Inserting record in Entity Framework without Foreign Key References

Please see below my ERD. Both Company and Contact can have ContactDetails and be Users at the same time. As such I haven't explicitly defined foreign key relationships with these tables. I user UserType (int) to determine whether it is Company or Contact and then store the relevant ID in the EntityId field.
Here is the code snippet I use to insert a new Company in the database.
public ActionResult Create(ProjectUser user)
{
if (ModelState.IsValid)
{
if (user.UserType == (int)PC.Utils.Enums.UserType.Company)
{
Company company = user.GetCompany(); // Get Company UI values from View Model
ContactDetail detail = user.GetContactDetail(); // Get Contact UI values from View Model
detail.UserType = (int)UserType.Company; // bind contact Type to Company Type
detail.EntityId = company.Id;
User login = user.GetLoginDetails(); // Get User UI values from View Model
login.UserType = (int)UserType.Company; // bind User Login to Company
login.EntityId = company.Id;
login.Password = PC.Utils.Security.GetMD5Hash(login.Password); // encrypt the password
db.Companies.Add(company);
db.ContactDetails.Add(detail);
db.Users.Add(login);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(user);
}
However, when I check the database the EntityId in both Users and ContactDetails table is 0, as EF did not determine the correct ID in the transaction. Is there something I am missing, or is there a nicer way to achieve this?

Entity framework - inserting by ID

I'm in a situation where I'm importing lots of "link" records from an XML file, and I want to insert them in my SQL link table using Entity Framework. My link table is literally just 2 columns, both of which are FKs and constitute the PK:
[UserAssessmentId] [int] NOT NULL
[AnswerId] [int] NOT NULL
The way I'm used to doing inserts involves the following:
Get the UserAssessment entity from the DB for userAssessmentId.
Get the Answer entity from the DB for answerId.
Add the Answer entity to the UserAssessment entity's Answers collection.
Repeat 2 and 3 for each answerId to add.
Call context.SaveChanges().
The trouble is that this is extremely DB intensive when adding hundreds of answers; EF has to get the record for each answer it is adding to the link table! I just want to insert a record with a given userAssessmentId, and a given answerId, and not go through the trouble of getting the entity first. EF needn't worry about whether the IDs I'm inserting are valid; just assume they are. Is there a way to get EF to do this or do I need to just use plain SQL?
The simplest option would probably be to create a separate context and a simple entity to represent your link table.
[Table("Name of the link table")]
public class UserAssessmentAnswer
{
public int UserAssessmentId { get; set; }
public int AnswerId { get; set; }
}
public class UserAssessmentAnswerContext : DbContext
{
public UserAssessmentAnswerContext()
: base("Connection string for the real context")
{
}
public IDbSet<UserAssessmentAnswer> UserAssessmentAnswers
{
get { return Set<UserAssessmentAnswer>(); }
}
}
Then you can use the new context and entity to insert your data:
using (var context = new UserAssessmentAnswerContext())
{
context.UserAssessmentAnswers.Add(new UserAssessmentAnswer
{
UserAssessmentId = ...,
AnswerId = ...
});
...
context.SaveChanges();
}
EDIT
You'll need to turn off database initialization for the new context. In your configuration file, add:
<entityFramework>
<contexts>
<context
type="YourNamespace.UserAssessmentAnswerContext, YourAssembly"
disableDatabaseInitialization="true"
/>
</contexts>
</entityFramework>
Or, you can add the following code to your startup:
Database.SetInitializer<UserAssessmentAnswerContext>(null);

ADO.NET Entity : getting data from 3 tables

I have following table structure:
Table: Plant
PlantID: Primary Key
PlantName: String
Table: Party
PartyID: Primary Key
PartyName: String
PlantID: link to Plant table
Table: Customer
PartyID: Primary Key, link to Party
CustomerCode: String
I'd like to have Customer entity object with following fields:
PartyID: Primary Key
CustomerCode: String
PartyName: String
PlantName: String
I am having trouble with PlantName field (which is brought from Plant table
I connected Customer to Party and Party to Plant with associations
However I can not connect Customer to Plant with association ( because it does not have one)
I can not add Plant table to mapping, when I do that - I am getting following error:
Error 3024: Problem in Mapping Fragment starting at line 352: Must specify mapping for all key properties (CustomerSet.PartyID) of the EntitySet CustomerSet
Removing Plant association works.
Any hints or directions very appreciated.
You can get these fields by using the reference path on the Entity Object.
To get the PartyName, use this syntax: Customer.Party.PartyName
To get the PlantName, use this syntax: Customer.Party.Plant.PlantName
You can extend the Customer entity by using the public partial class:
public partial class Customer
{
public string PartyName
{
get { return Party.PartyName; }
set { Party.PartyName = value; }
}
public string PlantName
{
get { return Party.Plant.PlantName; }
set { Party.Plant.PlantName = value; }
}
}
After some research, I came across this thread on MSDN that says you can create a read-only entity, which is enough of a downside to not use it alone, but it gets worse. You will also lose the ability to update all of the models dynamically based on the schema of the database.