Post an array of complex objects with JSON, MVC model is do not bind - arrays

here is my codes.
json_model
var mix = {
MixName: $("#mixname").val(),
MixDesc: tinyMCE.activeEditor.getContent(),
Price: $("#price").val(),
DiseaseMixs: [],
MixProducts: []
}
Add items to DiseaseMixs and MixProducts
$("#DiseaseList").find("tbody tr").each(function (index) {
mix.DiseaseMixs.push({
MixID: parseInt(MixID),
DiseaseID: parseInt($(".diseaseid").eq(index).html()),
ImpactDegree: parseInt($(".derece option:selected").eq(index).html()),
Description: $(".diseaseMixDesc input").eq(index).val()
});
})
$("#productList").find("tbody tr").each(function (index) {
mix.MixProducts.push({
MixID: parseInt(MixID),
ProductID: parseInt($(".productid").eq(index).html()),
MeasureTypeID: parseInt($(".birim option:selected").eq(index).val()),
MeasureAmount: $(".measureAmount input").eq(index).val()
});
})
and end of this process, here is a sample json object that is post.
{
"MixName": "asdasddas",
"MixDesc": "<p>sadasd</p>",
"Price": "123",
"DiseaseMixs": [{
"MixID": 1,
"DiseaseID": 2,
"ImpactDegree": 5,
"Description": "asads"
}, {
"MixID": 1,
"DiseaseID": 3,
"ImpactDegree": 4,
"Description": "aqqq"
}],
"MixProducts": [{
"MixID": 1,
"ProductID": 2,
"MeasureTypeID": 3,
"MeasureAmount": "3"
}, {
"MixID": 1,
"ProductID": 3,
"MeasureTypeID": 2,
"MeasureAmount": "45"
}]
}
ajax post
$.ajax({
url: 'SaveMix',
type: 'POST',
data: JSON.stringify(mix),
contentType: 'application/json; charset=utf-8',
success: function (result) {
console.log(result);
},
error: function (xhr, status) {
alert(status);
console.log(xhr);
}
})
and MVC Model and JSONResult function
Model
public class MixModel
{
public string MixName { get; set; }
public string MixDesc { get; set; }
public float Price { get; set; }
DiseaseMix[] DiseaseMixs { get; set; } //DiseaseMix EntityFramework entity
MixProduct[] MixProducts { get; set; } //MixProduct EF
}
function
[HttpPost]
public JsonResult SaveMix(MixModel mix)
{
bool result = false;
//do something
return Json(new { result = result }, JsonRequestBehavior.AllowGet);
}
and here is the result I get is.
No matter how I tried, I could not bind the model.
What am I doing wrong? Please give me some help.
Thanks in advance.

Model binding is failing because those 2 properties are currently private(which is the default when you don't specify anything explicitly).
Change the 2 properties to public so that model binder can set the values of those.
public class MixModel
{
public string MixName { get; set; }
public string MixDesc { get; set; }
public float Price { get; set; }
public DiseaseMix[] DiseaseMixs { get; set; } //DiseaseMix EntityFramework entity
public MixProduct[] MixProducts { get; set; } //MixProduct EF
}
I also suggests to not mix your view models with entities generated by your ORM. That creates a tightly coupled solution.

Related

EF Core self joined ICollection query

I have a problem with querying data from a self reference datatable having an ICollection.
Here are my table structures:
public class SoqHeading
{
public int Id { get; set; }
public string ItemNo { get; set; }
public string Heading { get; set; }
public SoqRevision SoqRevision_NP { get; set; }
public ICollection<SoqItem> Items { get; set; }
public int? ParentSoqHeadingId { get; set; }
public SoqHeading Parent_NP { get; set; }
public ICollection<SoqHeading> Children_NP { get; set; }
}
public class SoqItem
{
public int Id { get; set; }
public SoqPreliminaryOrContract_enum PreliminaryOrContract { get; set; }
public int SoqHeadingId { get; set; }
public SoqHeading SoqHeading_NP { get; set; }
}
I have a self referenced relation in the SoqHeading table which is 1 to many. The SoqHeading table can have zero or many SoqItems.
This is how the data is in my database
what i want is to query all from the root node of the SoqHeading table with its children and the items.
like this
{
"ItemNo": "C",
"Items": [
{
"ItemNo": "c-1",
},
{
"ItemNo": "c-2",
}
],
"Children_NP": [
{
"ItemNo": "C.1",
"Children_NP": [
{
"ItemNo": "C.1.1",
"Items": [
{
"ItemNo": "c.1.1-1",
},
{
"ItemNo": "c.1.1-2",
}
],
"Children_NP": [],
},
{
"ItemNo": "C.1.2",
"Items": [
{
"ItemNo": "c.1.2-1",
},
{
"ItemNo": "c.1.2-2",
}
],
"Children_NP": [],
}
],
},
{
"ItemNo": "C.2",
"Children_NP": [],
}
]
}
But currently i get data from the query like this
[
{
"ItemNo": "C"
},
{
"ItemNo": "C.1.2",
}
]
where C.1.2 has to be inside C, but it not. C and C.1.2 are in the same level which i dont wont to have produced by the following query
var entity = await _context.SoqHeadings
.Include(i=>i.Items)
.Include(i => i.Children_NP)
.Where(w => w.SoqRevision_NP.ProjectId == 10)
.ToListAsync();
please help
so it seems to be EFcore has no support to included the children on the first child node https://github.com/dotnet/efcore/issues/14144
so the work around is something like this here https://khalidabuhakmeh.com/recursive-data-with-entity-framework-core-and-sql-server

EF return columns data as list or array

I have two tables, which have following foreign key
Poll(CreatedBy) --> CreateBy(ID)
On performing join, I am getting data as following:
I want to write an query using EF (if possible) to return result as:
[{
"id": 1,
"users": [
{
"email": "abc.com"
}
]
},
{
"id": 3,
"users": [
{
"email": "xyz.test"
},
{
"email": "tet.com"
}
]
}]
Assuming that the class structure like below:
public class Poll
{
public int ID { get; set; }
public string Name { get; set; }
public List<CreateBy> CreateBy { get; set; }
}
public class CreateBy
{
public int ID { get; set; }
public string EmailAddress { get; set; }
public string DisplayName { get; set; }
[ForeignKey("Poll")]
public int PollId { get; set; }
}
Data source:
Linq query:
var result = (from p in _context.Poll.ToList()
join c in _context.CreateBy on p.ID equals c.PollId
group p by p.ID into g
select new
{
id = g.Key,
users = g.Select(x => x.CreateBy.Where(z => z.PollId == g.Key).Select(y => new { email = y.EmailAddress })).FirstOrDefault()
}).ToList();
Result:

"Movie" Model taking "Name" property of internal object "Actors"

I am new to Angular and Entity framework.
Here is the code from my AngularJS controller:
$scope.add = function () {
$scope.loading = true;
alert(this.newMovie.Name);
debugger;
$http.post('api/Movie/', this.newMovie).then(function onSuccess(response) {
alert("Added Successfully!!");
debugger;
$scope.showAddMovieForm = false;
$scope.movies.push(response);
$scope.loading = false;
}).catch(function (response) {
$scope.error = "An Error has occured while adding movie! :(" + response.data;
$scope.loading = false;
});
};
Here is how the Action method looks in my MovieController in MVC:
public HttpResponseMessage Post(Movie movie)
{
if (ModelState.IsValid)
{
// _db.People.Where(na => movie.Actors.Any(a => a.PersonId == na.PersonId));
_db.Movies.Add(movie);
_db.SaveChanges();
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, movie);
response.Headers.Location = new Uri(Url.Link("DefaultApi", new { movieId = movie.MovieId }));
return response;
}
else
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
}
}
Movie Model Class:
public partial class Movie
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Movie()
{
this.Actors = new HashSet<Person>();
}
public int MovieId { get; set; }
public string Name { get; set; }
public Nullable<short> YearOfRelease { get; set; }
public string Plot { get; set; }
public byte[] Poster { get; set; }
public Nullable<int> ProducerId { get; set; }
public virtual Person Producer { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Person> Actors { get; set; }
}
When I put a debugger in the JS code I can see that Angular is passing the object in correct format.
But somehow when it reaches Action, the "Movie" model takes "Name" property value "Actors" object which is part of "Movie" itself.
Not able to understand why "Movie" model is getting the "Name" property of "Actors".
You need to fix the way you are creating your Actors object in Movie object.
Actor should be JS Array of objects and your Movie object should look like below when you debug:
But, in your case Actors is just a single object. Hope it helps.

Getting null values in action with List parameter

Im passing array data from angularjs to mvc controller
This is my angularjs code
$http({
url: '/Login/InsertDetails',
method: 'POST',
data: JSON.stringify(Data),
headers: { 'content-type': 'application/json' }
})
Json Data is
$scope.details = [{
name: "ammin",
age: "16",
city: "NY",
add: "true",
sal: 100
}, {
name: "joe",
age: "80",
city: "CH",
add: false,
sal: 200
}];
var Data = {
one: $scope.details
}
And in my controller i have method Insert with list parameter
public JsonResult Insert(List<Personel> P)
{
}
View Model class is like this
public class Personel
{
public string name { get; set; }
public int age { get; set; }
public string city { get; set; }
public string add { get; set; }
public string sal { get; set; }
}
But im getting null values in action method when i post the data from angularjs. what type of parameter should i use in action method

Nancy with Complex object using JSON not working

Client code:
var basket = {
products: [],
user: { name: "schugh" }
};
$("#basket table tr").each(function (index, item) {
var product = $(item).data('product');
if (product) {
basket.products.push(product);
}
});
$.ajax({
url: "http://localhost:12116/basketrequest/1",
async: true,
cache: false,
type: 'POST',
data: JSON.stringify(basket),
contentType: 'application/json; charset=utf-8',
dataType: 'json',
success: function (result) {
alert(result);
},
error: function (jqXHR, exception) {
alert(exception);
}
});
Server code:
Post["/basketrequest/{id}"] = parameters =>
{
var basketRequest = this.Bind(); //basketrequest is null
return Response.AsJson(basketRequest , HttpStatusCode.OK);
};
Other model classes:
[Serializable]
public class BasketRequest
{
public User User;
public List<Product> Products;
}
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public string Category { get; set; }
public decimal Price { get; set; }
public ProductStatus ProductStatus { get; set; }
}
public enum ProductStatus
{
Created,
CheckedBy,
Published
}
public class User
{
public string Name { get; set; }
}
The code in the Nancy Module this.Bind(); returns null. If I change the Complex object to just List<Product>, i.e. with no wrapper BasketRequest, the object is fine...
Any pointers?
EDIT: JSON posted:
{
"User": {
"Name": "SChugh"
},
"Products": [{
"Id": 1,
"Name": "Tomato Soup",
"Category": "Groceries",
"Price": 1
}, {
"Id": 2,
"Name": "Yo-yo",
"Category": "Toys",
"Price": 3.75
}]
}
Your BasketRequest object should implement properties instead of fields. So
public class BasketRequest
{
public User User { get; set; }
public List<Product> Products { get; set; }
}
also you should probably use the generic method too
this.Bind<BasketRequest>();

Resources