I know there are some other questions regarding this-- but I was unable to get them to solve my problem.
I have the following classes:
public class Category
{
public Category()
{
Products = new List<Product>();
}
public int Id { get; set; }
public string Name { get; set; }
public List<Product> Products { get; set; }
public override string ToString()
{
return String.Format("{0}{1}", Id, Name);
}
}
and
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public Category Category { get; set; }
public override string ToString()
{
return String.Format("{0}{1}", Id, Name);
}
}
I've got some code which attempts to update both a product and it's category:
using (var ctx = GetCtx())
{
var beverages = new Category {Id = 1 };
var milk = new Product { Name = "MILK", Id = 4, Category = new Category { Id = 1} };
ctx.Entry(milk).State = System.Data.EntityState.Modified;
ctx.SaveChanges();
}
this results in the following sql statement:
update [dbo].[Products]
set [Name] = #0, [Price] = #1
where ([Id] = #2)
#0: MILK
#1: 0
#2: 4
I can't figure out how to make sure that the Category for the particular product is updated. I thought about adding a property to Product for Category_Id but this results in an additional column being generated in my database.
EDIT:
I think I figured this out-- after watching Julia Lerman's series on EF (Pluralsight)-- the way to set up this class is like this:
public class Product
{
public int Id { get; set; }
[Required]
[MaxLength(200)]
public string Name { get; set; }
public virtual Category Category { get; set; }
public int CategoryId { get; set; }
}
This results in only one foreign key column in the Products table. The Category of the Product gets updated when updating the CategoryId property.
You have to do two jobs, so do them in two operations...
var cat = ctx.Categories.FirstOrDefault(c=>c.Id == 1);
if(cat == null){
cat = new Category{Id=1};
ctx.Categies.Add(cat);
}
cat.Products.Add(new Product{Name="Milk", Id=4};
try{
ctx.SaveChanges();
}catch(Exception ex){
return RedirectToResponse("someone else got in first with that category Id");
}
Related
I Have two simple Models. Person and BankAccount.
public class Person
{
public int PersonId { get; set; }
public string FullName { get; set; }
public IList<Job> Jobs { get; set; }
public IList<BankAccount> BankAccounts { get; set; }
}
public class BankAccount
{
public int BankAccountId { get; set; }
public int Value { get; set; }
public Person Person { get; set; }
}
in the database, i have three rows.
now, i want to update value column of This person. This is my code:
var bankAccounts = new List<BankAccount>
{
new BankAccount {Value = 100},
new BankAccount {Value = 200},
new BankAccount {Value = 300},
};
var person = context.People
.Include(p => p.BankAccounts)
.FirstOrDefault(p => p.PersonId.Equals(12));
person.BankAccounts = bankAccounts;
context.SaveChanges();
after i run my code, i get bellow result:
how i can delete null rows? i want bellow result:
you are detaching old BankAccounts and attach new BankAccounts
first add public int PersonId { get; set; } to BankAccount class
then:
person.BankAccounts.ToList().AddRange(bankAccounts);
context.SaveChanges();
I have two tables Category and Document. See relationships in picture
See picture
I wrote the following query to select data from both tables based on relationship
public List<DocumentViewModel> All()
{
var docs = _context.Document.ToList();
List<DocumentViewModel> docList = docs.Select(x => new DocumentViewModel
{ DocumentId = x.DocumentId,
DocumentPath = x.DocumentPath,
CategoryId = x.CategoryId,
CategoryName = x.Category.CategoryName }).ToList();
return docList;
}
when this function is called , I get the following error
System.NullReferenceException: 'Object reference not set to an instance of an object.'
Here are my modals
document
public class Document
{
[Key]
public int DocumentId { get; set; }
[Required]
public string DocumentPath { get; set; }
public Nullable<int> CategoryId { get; set; }
public virtual Category Category { get; set; }
}
Category
public class Category
{
[Key]
public int CategoryId { get; set; }
[Required]
public string CategoryName { get; set; }
public virtual ICollection<Document> Documents { get; set; }
}
DocumentViewModel
public class DocumentViewModel
{
public int DocumentId { get; set; }
public string DocumentPath { get; set; }
public int? CategoryId { get; set; }
public string CategoryName { get; set; }
}
Any Idea where am doing mistake?
In this case there is no reason to get a List in memory and then do the projection, you can do this directly from EF instead. Even if there is no relationship defined EF will return null for CategoryName if you project the the results. If you go to memory first then an NRE is expected if there is no Category relationship.
public List<DocumentViewModel> All()
{
return _context.Document.Select(x => new DocumentViewModel
{ DocumentId = x.DocumentId,
DocumentPath = x.DocumentPath,
CategoryId = x.CategoryId,
CategoryName = x.Category.CategoryName}).ToList();
}
Original reason why it is failing.
There is at least one entity that does not have a corresponding relationship with Category.
You do not have lazy loading enabled (which is a good thing) and if that is the case you should use Include to return the relationship.
Hi every one I am new to ASP.Net Web API and I want to Post JSON array data any get there response.
My JSON POST Array format is
{
"User_Id":"admi12n#1234","Key_Code":"3F-47-AB-84-9F-EB-D6-6B-9C-62-CC-85-98-4D-28-6B",
"ProductDetails": [
{"Product_Id":"ELT-7035","Price":"999","Quantity":"5"},
{"Product_Id":"ELT-1254","Price":"1024","Quantity":"3"}
]
}
And I want response as follows
{
"User_Id":"admi12n#1234","Key_Code":"3F-47-AB-84-9F-EB-D6-6B-9C-62-CC-85-98-4D-28-6B",
"OrderID":"Ord-021","Name":"Sabyasachi"
"ProductDetails": [
{"Product_Id":"ELT-7035","Price":"999","Quantity":"5"},
{"Product_Id":"ELT-1254","Price":"1024","Quantity":"3"}
]
}
I generate OrderID as Random and Name from posted User_Id. Here I want to post multiple product in one order.
My Order class is as follows
public class Order
{
[Key]
public long ID { get; set; }
public string Order_Id { get; set; }
public string Product_Id { get; set; }
public long Quantity { get; set; }
public long Amount { get; set; }
public string User_Id { get; set; }
public string Key_Code { get; set; }
public DateTime Order_Date { get; set; }
public DateTime Modified_Date { get; set; }
}
And my Product class as follows
public class Product
{
[Key]
public int Id { get; set; }
public string Product_Code { get; set; }
public string Product_Name { get; set; }
public string Product_Category { get; set; }
public string Product_Description { get; set; }
public string Quantity { get; set; }
public string Price { get; set; }
public string Image { get; set; }
public DateTime Created_Date { get; set; }
public DateTime Modified_Date { get; set; }
}
I am not able to ind the best way to post the order
public Order Add(Order odrerDetails) //This will not give array of data for products
{
using (var context = new EcommerceDBContext())
{
odrerDetails.Order_Id = Helper.Random(7); //Generate random orderID from my class
odrerDetails.Created_Date = DateTime.Now;
odrerDetails.Modified_Date = DateTime.Now;
//How to Save other details
context.objOrderListing.Add(odrerDetails);
context.SaveChanges();
return odrerDetails;
}
}
In API controllers my code is as follows
public HttpResponseMessage PostOrder([FromBody] Order_Listing orderData)
{
orderData = repository.Add(orderData);
var response = Request.CreateResponse<Order_Listing>(HttpStatusCode.Created, orderData);
string uri = Url.Link("DefaultApi", new { customerID = orderData.ID });
response.Headers.Location = new Uri(uri);
return response;
}
Please help me how to achieve this.
There are several issues with your code:
Your Order and Product classes do not reflect the structure of
your JSON.
The Order class contains product details in a 1:1
relationship. Based on the JSON I assume you want a 1:n relationship.
Properties in your JSON need to have the same name as
in your classes or they won't be mapped.
Change your classes to the following and it should work.
Of course you could also change the property names in your JSON.
If you can't or don't want to change your property names, consider using DTOs
public class Order
{
public string User_Id { get; set; }
public string Key_Code { get; set; }
public string OrderID { get; set; }
public string Name { get; set; }
public List<Product> ProductDetails { get; set; }
// add the rest of your properties
}
public class Product
{
public string Product_Id { get; set; }
public string Price { get; set; }
public string Prd_Qty { get; set; }
// add the rest of your properties
}
Update: added code for Add method and Api method
Your Add method would look like this:
public Order Add(Order orderWithDetails)
{
using (var context = new EcommerceDBContext())
{
orderWithDetails.Order_Id = Helper.Random(7); //Generate random orderID from my class
orderWithDetails.Created_Date = DateTime.Now;
orderWithDetails.Modified_Date = DateTime.Now;
context.objOrderListing.Add(orderWithDetails);
// Save each Product
foreach (var detail in orderWithDetails.ProductDetails)
{
//whatever you need to do in your db-context
context.objOrderDetails.Add(detail); // just an example
}
context.SaveChanges();
return orderWithDetails;
}
}
The signature of your Api method looks wrong. What is Order_Listing? This should be Order, unless it's a DTO, in wich case you need a method to get an Order from Order_Listing.
public HttpResponseMessage PostOrder([FromBody] Order orderData)
{
orderData = repository.Add(orderData);
var response = Request.CreateResponse<Order_Listing>(HttpStatusCode.Created, orderData);
string uri = Url.Link("DefaultApi", new { customerID = orderData.ID });
response.Headers.Location = new Uri(uri);
return response;
}
A few more remarks:
If it is indeed a 1:n relationship, you probably need a property Product.OrderId.
The Order class should not have any reference to Product except for the list.
Quantity and Price should most likely not be String but numerical values, e.g. decimal.
If Order.ID is your primary key, then having Order.Order_ID is really confusing. Consider renaming it to Order.Order_Number.
public class Order
{
public string User_Id { get; set; }
public string Key_Code { get; set; }
public string OrderID { get; set; }
public string Name { get; set; }
public Product[] ProductDetails { get; set; }
}
I want to send a list of names contained in a Database using asp.net
These are my two objects:
public class Shop
{
public int ID { get; set; }
public string Country { get; set; }
public List<Item> Items{ get; set; }
}
public class Item
{
public int ID { get; set; }
public string Name { get; set; }
}
I want to set a get controller in order to retrieve a list of items.
I did something like this:
public IEnumerable<Item> Get(int id)
{
var items= new List<Item>();
var shop= new Shop();
using (var systemDB = new ShopsDB())
{
it = systemDB.Shops.Where(s => s.ID == id).FirstOrDefault<Shop>();
items = it.Items;
}
return items;
}
This return <ArrayOfItem i:nil="true"/>.
I want to get the complete list of Items for one shop (e.g. shop with ID=1)
This will return you the list
using (var systemDB = new ShopsDB())
{
lab = systemDB.Shops.Where(s => s.ID == id).ToList();
items = lab.Items;
}
I solved modifying the Item object:
public class Shop
{
public int ID { get; set; }
public string Country { get; set; }
public List<Item> Items{ get; set; }
}
public class Item
{
public int ID { get; set; }
public string Name { get; set; }
public int ShopID { get; set; }
}
And set a query to select the ShopID
Having trouble trying to turn an XDocument into an list of objects, in particular the Categories element. Below is a snippet of the XML which returns a list of shows in the following format.
<Show>
<Name>OLYMPIC GAMES</Name>
<Artist>OLYMPIC GAMES</Artist>
<OnSale>false</OnSale>
<DateOnSale>2011-03-11T00:00:00</DateOnSale>
<DoorsOpen>2012-12-31T10:00:00</DoorsOpen>
<Starts>2012-12-31T10:00:00</Starts>
<BespokeDate>25 July 2012 - 12 August 2012</BespokeDate>
<Status Code="3">SOLD OUT</Status>
<Categories>
<Category Id="190">OTHER</Category>
</Categories>
<Prices>
<Price Type="1">
<Status Code="24">ORDER</Status>
<FaceValue>0.00</FaceValue>
<BookingFee>0.00</BookingFee>
<TicketPrice>0.00</TicketPrice>
<Description>UNRESERVED</Description>
</Price>
</Prices>
<Venue Uri="/venues/">
<Name>Various venues</Name>
<Town></Town>
</Venue>
</Show>
Below is the classes I have created to model the XML data
public class Show {
public string Name { get; set; }
public string Artist { get; set; }
public bool OnSale { get; set; }
public DateTime DateOnSale { get; set; }
public DateTime DoorsOpen { get; set; }
public DateTime Starts { get; set; }
public string BespokeDate { get; set; }
public Status Status { get; set; }
public IEnumerable<Category> Categories { get; set; }
public Venue Venue { get; set; }
}
public class Status
{
public int Code { get; set; }
public string Description { get; set; }
}
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Venue
{
public string Uri { get; set; }
public string Name { get; set; }
public string Town { get; set; }
}
Below is the Linq to XML to create the Show objects
var shows = from s in xdoc.Descendants("Show")
where
s.Element("OnSale").Value.AsBool() != false
select
new Show {
Name = s.Element("Name").Value,
Artist = s.Element("Artist").Value,
OnSale = s.Element("Name").Value.AsBool(),
DateOnSale = s.Element("DateOnSale").Value.AsDateTime(),
DoorsOpen = s.Element("DoorsOpen").Value.AsDateTime(),
Starts = s.Element("Starts").Value.AsDateTime(),
BespokeDate = s.Element("BespokeDate").Value,
Status = new Status {
Code = s.Element("Status").Attribute("Code").Value.AsInt(),
Description = s.Element("Status").Value
},
Categories = (from c in s.Element("Categories").Elements("Category")
select new Category {
Id = s.Attribute("Id").Value.AsInt(),
Name = s.Value
}),
Venue = new Venue {
Name = s.Element("Venue").Element("Name").Value,
Town = s.Element("Venue").Element("Town").Value
}
};
Below is the code snippet to display a Show
foreach(var show in shows)
{
<p>
Name: #show.Name |
Status: #show.Status.Description |
Venue: #show.Venue.Name |
Categories: #string.Join(",", show.Categories.Select(x => x.Name))
</p>
}
The following error appears "Object reference not set to an instance of an object", whenever attempting to display categories. From what I can see, every show has 1 or more categories.
Any ideas?
This is the problem:
Categories = (from c in s.Element("Categories").Elements("Category")
select new Category {
Id = s.Attribute("Id").Value.AsInt(),
Name = s.Value
}),
You're using s.Attribute and s.Value instead of c.Attribute and c.Value.
I would also suggest using the explicit conversion to int instead of Value.AsInt():
Categories = (from c in s.Element("Categories").Elements("Category")
select new Category {
Id = (int) c.Attribute("Id"),
Name = (string) c.Value
}),