I'm using web api to send a list of an FSharp records to be put in a kendo grid
[<DataContract>]
type MyClass = {
[<field: DataMember(Name="Foo")>]
Foo: int
[<field: DataMember(Name="Bar")>]
Bar: DateTime option
}
$.getJSON(myUrl).done(function(data) {
console.log(data);
ds.data(data);
var grid = $('#myGrid').data("kendoGrid");
grid.setDataSource(ds);
When I see it in the grid, the int displays fine, but the "Bar" does not.
In the console:
Bar: Object
--Case: "Some"
--Fields: Array[1]
----0: "2014-12-18T17:01:34.0071449Z"
How do I handle this type of object in javascript? Or treat it like a nullable object?
Generally speaking, its best to avoid passing F#-specific types (like discriminated unions) to non-F# languages. You could perhaps use your data contract to transform your data into a more usable form during serialization. If you are using json.net you can use the examples here.
Related
I have a grid view whose data is based on a long value as the key and need that key for doing other operations (to find the record). The value is getting rounded up in the view when passed to an action:
ActionLink("some action", "some action", new{ key = "#=key#"}); // #= # is Kendo syntax
For example:
636280844960803997 is rounded to
636280844960804000
So what's the fix considering that I cannot add any attribute on that property in my model.
The problem is that JavaScript supports only 53-bit integers, which would make the largest supported integer to be 9007199254740991. Your key is larger than that. You can take a look at Number.MAX_SAFE_INTEGER (https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER)
The solution to this problem is to use string representations of your key on the client side. A good example of this is the Twitter API, where they return both an integer and a string: {"id": 10765432100123456789, "id_str": "10765432100123456789", ...}. There is a good article about it here: http://2ality.com/2012/07/large-integers.html
If you are using ASP.NET MVC I would recommend that you add another property to your model classes, which returns a ToString() version of your key. That way you can use the string version in JavaScript, while taking advantage of the numeric values within your database or server-side code. Here's an example
public class Item
{
public Item()
{
// ... your constructor code here ...
}
// Your long integer key
public Int64 ItemId { get; set; }
// The string version of your key
public string ItemIdString
{
get
{
return this.ItemId.ToString();
}
}
// The rest of your fields
// ...
}
Then you can use ItemIdString, when you bind your Kendo grid or anything else on the client side.
If you cannot modify the original class then I'd recommend that you create a subclass that inherits from the original one and add the ItemIdString property to that. Then just use the subclass to bind your grid.
You can used string instead of int in key field if possible so value can not be rounded
I'm trying to limit the amount of data coming across when implementing Lookup Lists in Breeze.JS. The Lookup Lists sample uses queries that results in full objects but I would like to project the entities to fewer properties (e.g. primary key, foreign keys, and a descriptor property) and still have Breeze.JS recognize the entity type on the client. I know how to do the projections from the client to get partials but how would I do that with Lookup Lists (either from the client or the server Web API)?
You might satisfy your intentions with a custom JsonResultsAdapter.
You're probably wondering "What is a JsonResultsAdapter?"
That's what breeze uses to interpret the JSON arriving from the server. You can read about here and here.
Perhaps more helpful is to look at the adapter in the Web API dataservice and at the example adapter from the "Edmumds" sample.
The Edmunds sample demonstrates translating a JSON source that you don't control into breeze entities.
In this case, your JsonResultsAdapter would look at each node of JSON and say "this is a Foo, this is a Bar, and that one is a Baz". Accordingly, for each of these nodes it would return { entityType: "Foo" }, return { entityType: "Bar" }, and return { entityType: "Baz" }
Now breeze knows what to do and creates corresponding entities out of the Lookups payload.
Remember to mark these entities as partial, in the same way you would if you had made a projection query that targeted a single entity type.
Fortunately, the Lookups query returns the container object that holds the Foo, Bar, and Baz collections. So you can iterate over these and mark them partial right there in the query success callback.
Once you wrap your head around THAT ... you'll want to know how to put your custom JsonResultsAdapter to work in the Lookups query ... and ONLY in the Lookups query.
You can enlist that JsonResultsAdapter exclusively for your Lookups query with a using clause.
Here's an example:
var jsa = new breeze.JsonResultsAdapter({
name: 'myLookupsJsa',
visitNode: function() {...}
});
query = query.using(jsa);
Is this overkill? Would you be better off making three trips?
Only you will know. I would like to hear from you when you try it ... and give us your suggestions on how we might make this easier in a general way.
In the lookup lists example the controller action looks like this:
[HttpGet]
public object Lookups() // returns an object, not an IQueryable
{
var regions = _contextProvider.Context.Regions;
var territories = _contextProvider.Context.Territories;
var categories = _contextProvider.Context.Categories;
return new {regions, territories, categories};
}
You could reduce the footprint using a server-side projection like this:
[HttpGet]
public object Lookups() // returns an object, not an IQueryable
{
var regions = _contextProvider.Context.Regions
.Select(x => new { id = x.RegionId, name = x.RegionName });
var territories = _contextProvider.Context.Territories
.Select(x => new { id = x.TerritoryId, name = x.TerritoryName });
var categories = _contextProvider.Context.Categories
.Select(x => new { id = x.CategoryId, name = x.CategoryName });
return new {regions, territories, categories};
}
This approach does not answer this part of your question:
and still have Breeze.JS recognize the entity type on the client
Not sure what the solution or use case is for this piece.
For example, if I have a record such as:
type sample = { userId : string; }
and then I define this record in C# such as:
var samp = new sample()
{
userId = null;
};
and then if I assign this record to an F# function called in C# what would happen? Is this legal? Would I just simply have to check for null within the F# function, or is this not possible?
Yes, in general, any reference type may be null. The F# compiler prevents null assignment to F#-specific types such as records and discriminated unions in F# code. However, it is still possible to assign null to variables of these types from C#.
String is a reference type and may be null, even from F#. Your C# code is slightly inaccurate in that the type sample would have userId in the constructor:
var samp = new sample(null);
If you annotate the sample type is CLIMutable attribute then it will also have a parameterless constructor.
So I have a class with a property like this:
public class Foo
{
[Column("GBBRSH")
public static string Gibberish { get; set;}
....
}
For saving data, I have it configured so that the update/insert statements use a custom function:
public static string GetTableColumnName(PropertyInfo property)
{
var type = typeof(ColumnAttribute);
var prop = property.GetCustomAttributes(type, false);
if (propr.Count() > 0)
return ((ColumnAttribute)prop.First()).Name;
return property.Name;
}
This handles fine, but I noticed that when I go to retrieve the data, it isn't actually pulling data back via the function for this particular column. I noticed that the other data present was pulled, but the column in question was the only field with data that didn't retrieve.
1) Is there a way to perhaps use the GetTableColumnName function for the retrieval part of Dapper?
2) Is there a way to force Dapper.NET to throw an exception if a scenario like this happens? I really don't want to have a false sense of security that everything is working as expected when it actually isn't (I get that I'm using mapping that Dapper.NET doesn't use by default, but I do want to set it up in that manner).
edit:
I'm looking in the SqlMapper source of Dapper and found:
private static IEnumerable<T> QueryInternal<T>(params) // my knowledge of generics is limited, but how does this work without a where T : object?
{
...
while (reader.Read())
{
yield return (T)func(reader);
}
...
}
so I learned about two things after finding this. Read up on Func and read up on yield (never used either before). My guess is that I need to pass reader.Read() to another function (that checks against column headers and inserts into objects appropriately) and yield return that?
You could change your select statement to work with aliases like "SELECT [Column("GBBRSH")] AS Gibberish" and provide a mapping between the attribute name and the poco property name.
That way, Dapper would fill the matching properties, since it only requires your POCO's to match the exact name of the column.
I have code that builds Urls in ASP.NET MVC3 using a RouteValueDictionary and UrlHelper. The problem that I am running into is that MVC calls ToString() on the types in the dictionary. For a particular type I am using, this is not the value that I want to be in the Uri. I cannot change the ToString implementation.
I understand how to create a ModelBinder to handle the deserialization from the Uri, but not the serialization part. How and what do I register in order to control how a type is converted to the Uri parameter?
Thanks,
Erick
For a particular type I am using, this is not the value that I want to be in the Uri
Then don't use this type. Pass the value that you want directly as string in the dictionary:
rvd["key"] = "the value you want";
instead of:
rvd["key"] = new SomeType { Foo = "foo", Bar = "bar" };
The conversion between your type and its string representation should be handled elsewhere.