I've configured my WebAPI ODATA service (using 5.0.0-rc1 for $expand and $select support) and everything seems to work fine but navigation properties.
The metadata does contain my navigation property (OpenPositions on Mandate) :
Then my breeze query is the following:
function search() {
var query = breeze.EntityQuery.from("Mandates").expand("OpenPositions").inlineCount();
return manager.executeQuery(query.using(service)).then(function (result) {
logger.info(result);
}).fail(function (error) {
logger.error(error);
});
}
The WebAPI controller :
[Queryable(AllowedQueryOptions= AllowedQueryOptions.All)]
public override IQueryable<Mandate> Get()
{
return new List<Mandate>() { new Mandate() {
Id = 1,
PolicyNumber = "350000000",
OpenPositions = new List<OpenPosition>(){
new OpenPosition(){ Id = 1, Amount = 2300, Mandate_Id = 1 },
new OpenPosition(){ Id = 2, Amount = 2100, Mandate_Id = 1 }
}},
new Mandate() {
Id = 2,
PolicyNumber = "240000000" ,
OpenPositions = new List<OpenPosition>(){
new OpenPosition(){ Id = 3, Amount = 2500, Mandate_Id = 2 },
new OpenPosition(){ Id = 2, Amount = 2100, Mandate_Id = 2}
}
} }.AsQueryable<Mandate>();
}
Nothing spectacular. But although my Mandate entities are coming back in the resultset, they do not have their OpenPositions collection.
As a test, if I add .select("OpenPositions") to my breeze query, then I get an error:
unable to locate property: OpenPositions on entityType: Mandate:#WebAPINoBreeze.Models
Why could that be ?
[EDIT]
query.entityType.NavigationProperties is an empty array, so that's probably a clue... It seems breeze could not build navigationproperties out of the metadata.
[EDIT]
foreign key added. problem still there:
public class Mandate
{
public int Id { get; set; }
public string PolicyNumber { get; set; }
public EStatus Status { get; set; }
public virtual List<OpenPosition> OpenPositions { get; set; }
}
public class OpenPosition
{
public int Id { get; set; }
public decimal Amount { get; set; }
[ForeignKey("Mandate")]
public int Mandate_Id { get; set; }
}
**[EDIT] **
For some reasons the [ForeignKey("Mandate")] attribute was removed at compile time (I think it's because the model class is generated. I've found a workaround and the metadata now contains the foreign key MandateId to Mandate in the OpenPositions :
You must define a foreign key as Breeze associations require FKs. http://www.breezejs.com/documentation/navigation-properties
[EDIT]
Your bi-directional association should look like this:
public class Mandate
{
public int Id { get; set; }
public string PolicyNumber { get; set; }
public virtual ICollection<OpenPosition> OpenPositions { get; set; }
}
public class OpenPosition {
public int Id { get; set; }
public decimal Amount { get; set; }
public int MandateId { get; set; }
public Mandate Mandate {get; set; }
}
Related
I have two simple models:
Book:
public class Book
{
public int BookID { get; set; }
public string Name { get; set; }
public string Author { get; set; }
public string Year { get; set; }
public string Publisher { get; set; }
public int GenreId { get; set; }
[ForeignKey("GenreId")]
public Genre Genre { get; set; }
}
and Genre
public class Genre
{
public Genre()
{
Books = new List<Book>();
}
public int GenreID { get; set; }
public string Name { get; set; }
public ICollection<Book> Books { get; set; }
}
With method from ApiController I get all data from table Books.
How can I get in javascript code Name of genre from table Genres using foreign key GenreId ?
I would like to write something like book.Genre.Name, but it does not work in js
You can try below code to serialize the object to return to frontend with json format:
var genre = new Genre();
JavaScriptSerializer js = new JavaScriptSerializer();
string data = js.Serialize(Genre);
Or in other way, you can use Json.NET for do that, this is a powerful json object convert lib.
I'm still new to mvc5 and had very little knowledge with javascript. I know that my cascading works but I'm having trouble with the display part. What I want to do is have 2 dropdown list. 1 containing all customer names and the 2nd will have a list of their pending transactions. Basically 1st dropdown will have customer names while the 2nd will have video titles. Please check my code where I did wrong. Why I can't display the video titles. BTW I tried other properties in my transactions and I can display them. That's how I know that my cascading is not the problem.
Models
//Transaction Model
TransactionID { get; set; }
public int CustomerID { get; set; }
public virtual Customers CustomerName { get; set; }
public int VideoID { get; set; }
public virtual Videos Videos { get; set; }
public int Quantity { get; set; }
[ReadOnly(true)]
public DateTime? TransactionDate { get; set; }
[ReadOnly(true)]
public DateTime? DueDate { get; set; }
[ReadOnly(true)]
public Decimal Cost { get; set; }
[ReadOnly(true)]
public String ReturnStatus { get; set;}
//Customers Model
public int CustomerID { get; set; }
public string CustomerName { get; set; }
public string CustomerAddress { get; set; }
public string CustomerContact { get; set; }
//Video Model
public int VideoID { get; set; }
public string VideoTitle { get; set; }
public int CategoryID { get; set; }
public virtual Category VideoCategory { get; set; }
[Range(0,99)]
public int VideoIn { get; set; }
[Range(0,99)]
public int VideoOut { get; set; }
Conroller
public ActionResult CustomerList()
{
var customers = db.Customers.OrderBy(x => x.CustomerID).ToList();
if (HttpContext.Request.IsAjaxRequest())
{
return Json(new SelectList(
customers,
"CustomerID",
"CustomerName"), JsonRequestBehavior.AllowGet
);
}
return View(customers);
}
public ActionResult Transact(int cusId)
{
var transact = db.Transactions
.Where(x => x.CustomerID == cusId)
.Where(s => s.ReturnStatus == "FALSE").ToList();
if (HttpContext.Request.IsAjaxRequest())
return Json(new SelectList(
transact,
"TransactionID",
"VideoTitle"), JsonRequestBehavior.AllowGet
);
return View(transact);
}
I figure out a solution after hours of trial an error. What I did is I added a join in my query.
var transact = db.Transactions
.Where(x => x.CustomerID == cusId)
.Where(s => s.ReturnStatus == "FALSE")
.Join(db.Videos,
v => v.VideoID,
t => t.VideoID,
(transaction, videos) => new {
TransactionID = transaction.TransactionID,
VideoTitle = videos.VideoTitle }).ToList();
I have a treeview in kendoUI in which main nodes are calling into an mvc controller and that controller looks to whether there is an nullable id passed in and then uses a different model.
What I hit the url : http://localhost:2949/Report/GetReportGroupAssignments
I see this JSON
[
{"Id":1,"ReportGroupName":"Standard Reports","ReportGroupNameResID":null,"SortOrder":1},
{"Id":2,"ReportGroupName":"Custom Reports","ReportGroupNameResID":null,"SortOrder":2},
{"Id":3,"ReportGroupName":"Retail Reports","ReportGroupNameResID":null,"SortOrder":3},
{"Id":4,"ReportGroupName":"Admin Reports","ReportGroupNameResID":null,"SortOrder":5},
{"Id":5,"ReportGroupName":"QA Reports","ReportGroupNameResID":null,"SortOrder":4}
]
Now my mvc controller looks like this
public JsonResult GetReportGroupAssignments(int? id)
{
var model = new List<ReportGroup>();
var defModel = new List<ReportDefinition>();
try
{
if (id == null)
{
model = _reportService.GetReportGroups("en-us").ToList();
return Json(model, JsonRequestBehavior.AllowGet);
}
else
{
defModel = _reportService.GetReportDefinitions().Where(e=>e.ReportGroupID ==Convert.ToInt32(id)).ToList();
return Json(defModel, JsonRequestBehavior.AllowGet);
}
}
catch (Exception ex)
{
Logger.Error(ex, "Error loading LoadReportList.");
return null;
}
}
My Kendo javascript looks like the following:
var serviceRoot = "/Report"; // "//demos.telerik.com/kendo-ui/service";
homogeneous = new kendo.data.HierarchicalDataSource({
transport: {
read: {
url: serviceRoot + "/GetReportGroupAssignments", //"/LoadReportTree", // "/Employees",
dataType: "json"
}
},
schema: {
model: {
id: "Id" //"ReportGroupName"
,hasChildren: "Id"
}
}
});
var treeview = $("#treeview").kendoTreeView({
expanded: true,
dragAndDrop: true,
dataSource: homogeneous,
dataTextField: "ReportGroupName"
}).data("kendoTreeView");
Seems that the calls (which I discovered that children records have a "load" method that it called behind the seens, so basically I pass in the ID in order to get the data from the other model ( table in db)
(Id is mapped with automapper to ReportGroupID )
So when i click to the left of "Standard Rports" I am getting all of these children as undefined, How do I get these to show up properly?
Update: My ReportDefinition class:
public class ReportDefinition {
public override int Id { get; set; }
public string ReportKey { get; set; }
public string ReportName { get; set; }
public int? ReportNameResID { get; set; }
public string ReportDef { get; set; }
public int? ReportDefinitionResID { get; set; }
public string ReportAssembly { get; set; }
public string ReportClass { get; set; }
public int ReportGroupID { get; set; }
public int AppID { get; set; }
public int SortOrder { get; set; }
public bool IsSubReport { get; set; }
}
I think your problem is that the class ReportDefinition does not have a property called: ReportGroupName. That is why TreeView displays 'undefined'.
Try adding this Property to your ReportDefinition class like:
public class ReportDefinition {
// Other Properties
// I guess this property is missing
public string ReportGroupName { get; set; }
}
I am trying to create a new row in a table I have hosted in Azure SQL Database. My front end is AngularJS with C# in .NET as the back end.
Here is my code from the front end passing the object:
var insertTicket = function (newTicket) {
return $http.post("http://localhost:50412/api/tickets", JSON.stringify(newTicket))
.then(function (response) {
console.log(response);
console.log("Insert Successful");
return;
});
And here is my backend code that receives the data and tries to add to the database:
[Route("api/tickets")]
public HttpResponseMessage Post(Ticket t)
{
TicketsRepository.InsertTicket(t);
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK);
return response;
}
In TicketRepisitory:
public static void InsertTicket(Ticket tick)
{
var maxID = (from ticket in dataContext.Tickets
select ticket.id).Max();
var tick = new Ticket();
tick.id = maxID + 1;
dataContext.Tickets.Add(tick);
dataContext.SaveChanges();
}
And Here is my Ticket class:
public partial class Ticket
{
//Properties
public int id { get; set; }
public string title { get; set; }
public string customer { get; set; }
public string barcode { get; set; }
public string assignedTo { get; set; }
public string category { get; set; }
public string importance { get; set; }
public Nullable<System.DateTime> openDate { get; set; }
public Nullable<System.DateTime> dueDate { get; set; }
public Nullable<System.DateTime> closedDate { get; set; }
public string comments { get; set; }
public string condition { get; set; }
public Nullable<int> workHours { get; set; }
//Relationships
public Employee Employee { get; set; }
public Employee Employee1 { get; set; }
public Equipment Equipment { get; set; }
}
I think the issue is with Post() expecting a ticket object. I have tried searching for how to receive JSON data and use that for Ticket, but with out much luck.
My Problem is that I can not create a new row. No changes are reflected in my database.
You don't need to JSON.stringify your object when POSTing data with $httpin AngularJS, just pass the object itself as the second parameter, like this:
var insertTicket = function (newTicket) {
return $http.post("http://localhost:50412/api/tickets", newTicket)
.then(function (response) {
console.log(response);
console.log("Insert Successful");
return;
});
First there is no need to call JSON.stringify() method on newticket javascript object for second paramter of $http.post() method.
Then in the web api method write a parameter of type JObject with the name newTicket to receive the posted object, and use generic version of ToObject method to convert posted data to desired type. Don't forget to use [FromBody] attribute for the method parameter. the code for webapi looks like this:
[Route("api/tickets")]
public HttpResponseMessage Post([FromBody]JObject newTicket)
{
var t = newTicket.ToObject<Ticket>();
TicketsRepository.InsertTicket(t);
HttpResponseMessage = Request.CreateResponse(HttpStatusCode.OK);
return response;
}
I’m developing a custom data access layer to be consumed in breeze.js
What I have:
The Model:
public class Product
{
[Key]
public int ProductId { get; set; }
public string Upc { get; set; }
public string Name { get; set; }
public decimal MsrpPrice { get; set; }
public int Quantity { get; set; }
public virtual ICollection<ProductFeature> Features { get; set; }
public virtual B2BCategory InB2BCategory { get; set; }
public virtual ICollection<ImageDescriptor> Images { get; set; }
public int CategoryId {get; set;}
}
public class ProductFeature
{
public int ProductId { get; set; }
public string Name { get; set; }
public string GroupName { get; set; }
public string Operation { get; set; }
public decimal Value { get; set; }
}
public class ImageDescriptor
{
public int ProductId { get; set; }
public string Uri { get; set; }
public DateTime Updated { get; set; }
public bool IsDefault { get; set; }
}
The Context Provider:
public class ProductContextProvider : ContextProvider
{
private readonly ProductRepository repo =new ProductRepository();
public IQueryable<B2BCategory> Categories
{
get { return repo.Categories.AsQueryable(); }
}
public IQueryable<Product> Products
{
get
{
return repo.Products.OrderBy(p => p.ProductId).AsQueryable();
}
}
protected override string BuildJsonMetadata()
{
var contextProvider = new EFContextProvider<ProductMetadataContext>();
return contextProvider.Metadata();
}
protected override void SaveChangesCore(SaveWorkState saveWorkState)
{…
}
// No DbConnections needed
public override IDbConnection GetDbConnection()
{
return null;
}
protected override void OpenDbConnection()
{
// do nothing
}
protected override void CloseDbConnection()
{
// do nothing
}
}
internal class ProductMetadataContext : DbContext
{
static ProductMetadataContext()
{
Database.SetInitializer<ProductMetadataContext>(null);
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new ProductFeatureConfiguration());
modelBuilder.Configurations.Add(new ImageDescriptorConfiguration());
}
public DbSet<Product> Products { get; set; }
public DbSet<B2BCategory> Categories { get; set; }
}
internal class ImageDescriptorConfiguration : EntityTypeConfiguration<ImageDescriptor>
{
public ImageDescriptorConfiguration()
{
// I tried to mess up with key orders
HasKey(i => new { i.Uri, i.ProductId});
}
}
internal class ProductFeatureConfiguration : EntityTypeConfiguration<ProductFeature>
{
public ProductFeatureConfiguration()
{
HasKey(f => new { f.ProductId, f.Name });
}
}
I’m stuffing the Features and Images properties of a Product directly:
product.Features = new Collection<ProductFeature>();
product.Images = new Collection<ImageDescriptor>();
…
var imgd = new ImageDescriptor
{
ProductId = product.ProductId,
Updated = DateTime.Now,
Uri = defsmall,
IsDefault = !product.Images.Any()
}
product.Images.Add(imgd);
…
var pf = new ProductFeature
{
ProductId = product.ProductId,
GroupName = "Size",
Name = size,
Value = size == "Small" ? new decimal(.75):size == "Medium" ? new decimal(1.3):new decimal(1.8),
Operation = "*"
};
product.Features.Add(pf);
Totally there are, say, 3 product features and 2 images per product item.
In the client side I query this like:
return entityQuery.from('Products').using(EntityManager).execute();
And… I’ve got the very strange thing:
The images property contains an empty array, the features property contains an array of 5!!! elements – 3 of type ProductFeature and 2 of type ImageDescriptor.
I think this is a bug – could you help me, please?
I don't see any code that creates a breeze EntityManager and adds or attaches your newly created entities and then saves them. Please take a look at the Breeze examples in the downloadable zip from the BreezeJs website.