Assign new values in a Breeze entity - javascript

I'm developing a spa web application with BreezeJS and the DurandalJS Framework. I came accross a problem which I can't fix.
I have a entity called: Car, this entity contains name, number, owner, type en manufacturer. In this entity the name and number are filled in as the entity is created AND saved in the database. The other properties are allowed to be NULL.
This because the other values are filled in during a modal/ dialog screen. Here a user can select a owner from a list and also a type and manufacturer from a list. When the user selects one from a dropdown the selected value should be assigned to the value of the Car entity. How can I get this to work?
Car().Owner = newOwner;
Car.Owner() = newOwner;
This won't work. I tried a lot of combinations. Remember that the value was null first and that I can't insert a new value;S
Edit 1
Here the Entity Framework model of Car
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Estimate_App.Models
{
public class tblCar
{
[Key]
public int CarID { get; set; }
public string CarNumber { get; set; }
private DateTime _CreationDate;
public DateTime CreationDate
{
get { return this._CreationDate; }
set { this._CreationDate = DateTime.Now; }
}
//This is the Owner
[ForeignKey("Owner")]
public int? OwnerID { get; set; }
public tblOwner Owner { get; set; }
}
}
Here is what I put in my Car().Owner(), consider Container should be Car (this is an other project with the same problem)
I hover my mouse over newValue.
Edit 2
By a answer of Julián Yuste I also tried this but it didn't work. Here is the error:
When I do Container().Owner(newValue);
Edit 3
The code that fetches the owners
breeze.EntityQuery.from("Customers")
.using(dataservice.manager)
.execute().then(function (data) {
data.results.forEach(function (item) {
tempCustomerList.push(item); //ko.observableArray([]);
});
}).fail(function (data) {
});

Are you using the EntityManager from your dataservice object in order to create the newOwner object?
In other words, you probably shouldn't be doing this*:
var newOwner = new Owner();
newOwner.OwnerID = 123;
You should do this:
var newOwner = dataservice.manager.createEntity('Owner', { OwnerID: 123 });
*Note that can actually use new Owner(), but that requires you to define entity constructors in your code. :-)
For more information, check out the Breeze documentation: http://www.breezejs.com/documentation/creating-entities
Also, note that you can read the Breeze JavaScript code to help you understand the issue. If you search breeze.debug.js for your error message (An Entity cannot be attached to an entity in another EntityManager. One of the two entities must be detached first.), you will find the line of code that is causing the exception. It may be helpful to backtrack from there.
Edit
The answer to the question was to make sure that the EntityManager object is a Singleton (in this case, the dataservices.manager object).
In other words, use the same EntityManager object to update objects as you use to query for objects.

I think we need more information. Is the 'Owner' property an instance of another entity or is it a primitive type, i.e. string, number etc?
If it is an entity then I would first check that your 'newOwner' variable was also in fact an entity.

If owner is an observable, you need to asign the new value as: owner(newOwner).
Greetings.

Related

Serialize form to string and deserealize it later to complex view model

I'm implementing the "Save Draft" functionality on my dynamically generated page and trying to make it as generic as possible. All my controllers and pages should support it and that's why I thought about creating a SaveDraft() POST action in my base controller which will receive a serialized form as a string which can be directly saved into the database and deserialized to a view model later in the specific get action using specific view model
[HttpPost]
public ActionResult SaveDraft(string jsonData, long id)
My first idea was to create the generic base controller and pass the view model type to it but the problem is that some controllers have multiple differently named POST actions and using different view model types, I cant change it now.
Some view models are complex and looking like
public class CollateralsDataModel
{
//...
public List<Applicant> Applicants { get; set; }
}
public class Applicant
{
public long ApplicantId { get; set; }
public IList<RealEstateSecurityCollateralsDTO> RealEstateSecurityCollaterals { get; set; }
public IList<AdditionalCollateralDTO> AdditionalCollaterals { get; set; }
}
public class RealEstateSecurityCollateralsDTO
{
[Required]
[Display(ResourceType = typeof(CollateralsData), Name = nameof(CollateralsData.RealEstateSecurityType))]
public int? RealEstateSecurityTypeId { get; set; }
//...
}
The input names on the form are looking like
"Applicants[0].MortgageApplicantId": "11595",
"Applicants[0].RealEstateSecurityCollaterals[0].Id": "17",
"Applicants[1].MortgageApplicantId": "11596",
"Applicants[1].RealEstateSecurityCollaterals.Index": "0",
"Applicants[1].AdditionalCollaterals[0].Id": "138",
"Applicants[1].AdditionalCollaterals[0].AdditionalCollateralTypeId": "4",
My question is - how can I serialize them to the string so I can deserialize it later?
I tried using different combinations of
$('.draft-data-form').serializeArray()
$('.draft-data-form').serialize()
JSON.stringify($('.draft-data-form').serializeArray());
but in my Action I get the flat JSON structure and I can't deserialize it
var obj = JsonConvert.DeserializeObject<CollateralsDataModel>(jsonData);
Cannot deserialize the current JSON array (e.g. [1,2,3]) into type '...CollateralsDataModel' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly.
To fix this error either change the JSON to a JSON object (e.g. {"name":"value"}) or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array.
I've also tried to deserialize it as a list but then I get the List of 115 entries
var obj = JsonConvert.DeserializeObject<List<CollateralsDataModel>>(jsonData);
So my question is - how can I serialize them to the string so I can deserialize it later?
You do not want to serialize/deserialize a List. Only a single instance of the model.
I would guess that the error is in instantiating the list within the model. I know that the DataContractSerializer has an issue where if the List is not instantiated to an empty list when the model is constructed then the deserialization is unable to add to it.
Not sure if this is the same problem you are facing but could be worth a try.
eg. use:
public List<Applicant> Applicants { get; set; } = new List<Applicant>();

SignalR: exclude non serializable types

I have a class like this:
public class MyData
{
public int Id { get; set; }
public String Name { get; set; }
public ThirdPartyClass { get; set; } // non serializable
}
I said "non-serializable" because when I pass my class to a SignalR client function in this way:
var hub = GlobalHost.ConnectionManager.GetHubContext<MyHub>();
var myData = new MyData();
// fill fields
hub.Clients.All.data(myData);
the call return error 500.
Removing the offending field it work as expected.
Please, note I'm not interested to pass to the client that field.
Right now I know two ways to solve this:
write a custom json serializer
create a shadow class with only the relevant fields, copy the values, and send this class to the clients
Both are uncomfortable when you have dozen of fields.
I'm wondering if there's some DataAnnotation I might use to exclude a field from serialization.
You can use IgnoreDataMemberAttribute() but I'm not sure if that would work with SignalR.
Your alternative if that doesn't work is the JsonIgnore annotation.
Lastly, there is also ScriptIgnore.
IgnoreDataMember Class Reference

Is there way to update an entity properties and add a reference to it through one single PATCH-request in OData v4?

In context of the WCFService with the OData v2 support, I was able to perform a single MERGE request which will change property values of the entity and the references owned by it (through the __metadata object of the request payload).
I've read about $ref requests in OData v4 and CreateRef technique, but it will cost two requests. One to change property values of the entity and the other one to change entity references.
Is there a way to patch an entity and edit its references in one single request in WebAPI with the OData v4 support?
If you have a 1:n relation you can easily set the foreign key in the request. However your Model must provide a link to the foreign key. Here is an example model (code first):
public class Project
{
public int ProjectId { get; set; }
public string Name { get; set; }
public int ManagerId { get; set; }
[ForeignKey("ManagerId")]
public Person Manager { get; set; }
}
In an m:n relation this is not possible because of it's design (EF automatically create a relation table.). However, you can use a custom action an implement the relationship building on your own.

Error using dynamic keyword in asp.net mvc 4

I am getting this long error when i accpet the parameter as dynamic on my server side action method in mvc 4.
{"Message":"An error has
occurred.","ExceptionMessage":"'Newtonsoft.Json.Linq.JObject' does not
contain a definition for
'TournamentId'","ExceptionType":"Microsoft.CSharp.RuntimeBinder.RuntimeBinderException","StackTrace":"
at CallSite.Target(Closure , CallSite , Object )\r\n at
System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite
site, T0 arg0)\r\n at
ManagerDeTorneos.Web.Controllers.TournamentDateController.Create(Object
data) in
F:\Prince\Projects\Juan\trunk\ManagerDeTorneos.Web\Controllers\TournamentDateController.cs:line
133\r\n at lambda_method(Closure , Object , Object[] )\r\n at
System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c_DisplayClass13.b_c(Object
instance, Object[] methodParameters)\r\n at
System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object
instance, Object[] arguments)\r\n at
System.Threading.Tasks.TaskHelpers.RunSynchronously[TResult](Func`1
func, CancellationToken cancellationToken)"}
[HttpPost]
public HttpResponseMessage AddMatch(dynamic data)
{
int tournamentDateId = (int)data.TournamentDateId.Value;
var tournamentDate = Catalog.TournamentDateRepository.GetById(tournamentDateId);
if (tournamentDate == null)
{
throw ExceptionHelper.NotFound("Fecha no encontrada!");
}
In The above method data Contains tournamentId as sent from ajax call as JSON.Stringify({'TournamentId':'5'}).
Can anybody tell me what is the cause of error. I even replaced the dll of Newtonsoft.Json as well
You are right dan but i fixed my issue by removing that dll from GAC. May be in GAC it was using old assembly
The error is caused by the fact that you typed your parameter as dynamic, which means that the model binder doesn't know what to make it. It's the same as if you were to declare it as an object. Since you are providing JSON, it serializes the object as a Json.Net JObject. Just because you define it as a dynamic doesn't mean that it's going to magically take whatever shape you need it to.
Change it to a concrete type - something that matches the structure of the provided JSON:
public class TournamentInfo
{
public int TournamentId { get; set; }
}
[HttpPost]
public HttpResponseMessage AddMatch(TournamentInfo data)
{
int tournamentDateId = data.TournamentId;
var tournamentDate = Catalog.TournamentDateRepository.GetById(tournamentDateId);
if (tournamentDate == null)
{
throw ExceptionHelper.NotFound("Fecha no encontrada!");
}
This way, the binder knows what it's supposed to turn the JSON into, and since TournamentInfo matches the structure of the JSON, it won't have any trouble serializing it.
Don't misuse dynamic. It was not introduced into C# so developers could stop defining classes.

Model DataAnnotation for asp.net mvc

Is there any way to get dataanotations for my models directly from my database?
I have a database with lot's of data and tables, so i am generating my model with entity framework from database, so i get classes, but i want to know can entity framework or some other orm get properities and constrains directly from database and put them in classes as data anotation like [required] or [datatype(datatype.emailadress)]
Yes. You can inherit the ModelMetadataProvider class:
public class LocalizedModelMetadataProvider : DataAnnotationsModelMetadataProvider
{
protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType,
Func<object> modelAccessor, Type modelType, string propertyName)
{
var metadata = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);
if (containerType == null || propertyName == null)
return metadata;
// Load all metadata from your database here.
return metadata;
}
}
I'm creating a project called Griffin.MvcContrib which is almost done and has a administration area where you can handle all localization (zero-code) for both models and validation messages.
By using it you can just implement the following interface to get support for your database:
// the actual code file has detailed explanations of each method.
public interface ILocalizedStringProvider
{
string GetModelString(Type model, string propertyName);
string GetModelString(Type model, string propertyName, string metadataName);
string GetValidationString(Type attributeType);
string GetEnumString(Type enumType, string name);
}
Update
Where is not important. And you do not have to use DataAnnotation attributes on your models (the [Display] attribute). I just inherit the DataAnnotationsModelMetadataProvider to be able to use the attributes.
Create the class anywhere.
Read from the database
Configure MVC to use it in global.asax
Example:
ModelMetadataProviders.Current = new YourModelMetadataProvider();

Categories

Resources