I know that in F# if you have a C# class of the format:
public class Person {
public DateTime BirthDate { get; set; }
public string Name { get; set; }
}
You can initialize it like so, which is nice:
let p = new Person (Name = "John", BirthDate = DateTime.Now)
However how would you initialize it in F# if the C# class also had a constructor like this:
public class Person {
public Person(int id)
{
Id = id
}
public int Id {get; private set;}
public DateTime BirthDate { get; set; }
public string Name { get; set; }
}
Are we forced to use this structure instead?
let p = new Person (123)
p.Name <- "John"
p.BirthDate <- DateTime.Now
Using the equivilent F# syntax for auto properties might look like this. You are able to combine the constructor and property initialization as follows:
type Person(id : int) =
member val Id = id with get,set
member val BirthDate = DateTime.MinValue with get,set
member val Name = "" with get,set
let p = Person(5, Name = "Stu")
p |> Dump
The System.UriBuilder BCL class looks like the Person class in the OP, so I'll use that as an example:
> let ub = UriBuilder("http://blog.ploeh.dk", Path = "about");;
val ub : UriBuilder = http://blog.ploeh.dk:80/about
Related
I am trying to retrieve the Person name in my viewmodel while projection in the below code:
// GET api/Tickets
public IQueryable Get()
{
var model = Uow.Tickets.GetAll().OrderByDescending(m => m.DateTimeTag)
.Select(m => new TicketViewModel
{
Id = m.Id,
TicketTitle = m.TicketTitle,
TicketBody = m.TicketBody,
DateTimeTag = m.DateTimeTag,
//AssignedTo = Uow.Persons.GetById(m.AssignedToPersonId).Name,
Status = m.Status.ToString(),
NoOfReplys = m.Replys.Count()
});
return model;
}
But when I uncomment the AssignedTo line, it gives me the error:
InnerException: {
Message: "An error has occurred.",
ExceptionMessage: "LINQ to Entities does not recognize the method 'Ticketing.Model.Person GetById(Int32)' method, and this method cannot be translated into a store expression.",
ExceptionType: "System.NotSupportedException",
StackTrace: " at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.DefaultTranslator.Translate(ExpressionConverter parent, MethodCallExpression call) at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.TypedTranslate(ExpressionConverter parent, MethodCallExpression linq) at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TypedTranslator`1.Translate(ExpressionConverter parent, Expression linq) at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq) blah blah blah
The TicketViewModel class is:
public class TicketViewModel
{
public int Id { get; set; }
public string TicketTitle { get; set; }
public string TicketBody { get; set; }
public DateTime DateTimeTag { get; set; }
public string AssignedTo { get; set; }
public string Status { get; set; }
public int NoOfReplys { get; set; }
}
The actual Ticket class is:
public class Ticket
{
public int Id { get; set; }
public string TicketTitle { get; set; }
public string TicketBody { get; set; }
public DateTime DateTimeTag { get; set; }
public int AssignedToPersonId { get; set; }
public Status Status { get; set; }
public virtual ICollection<Reply> Replys { get; set; }
}
My desired output is:
[
{
Id: 3,
TicketTitle: "a problem",
TicketBody: "problem descripted here.",
DateTimeTag: "2012-04-21T00:00:00",
AssignedTo: "Peter", <== ATTENTION!!!
Status: "Open",
NoOfReplys: 0
}
]
Here, Peter is the name of the person who its id is in the ticket object.
My goal is to show the name instead of personId.
may be there is a better way, please help me do that.
thanks
In this case I think that your property:
public int AssignedToPersonId { get; set; }
should be:
public Person AssignedToPerson { get; set; }
in your Ticket class. Mapping to the reference is generally better so that you can access properties like this using Linq. This way the line that is giving you trouble can be:
AssignedTo = AssignedToPerson.Name
The reason it isn't working right now is because Entity Framework has no idea how to convert your line:
Uow.Persons.GetById(m.AssignedToPersonId).Name
to a Query expression. By using a reference mentioned above you will instead create a Join between the two tables and get back the desired data in a single query.
The other and probably less attractive option is to store the Id in your View Model and then do a query for the name outside your Linq query. This will work because you have already retrieve items from the database. Untested example below:
public IQueryable Get()
{
var model = Uow.Tickets.GetAll().OrderByDescending(m => m.DateTimeTag)
.Select(m => new TicketViewModel
{
Id = m.Id,
TicketTitle = m.TicketTitle,
TicketBody = m.TicketBody,
DateTimeTag = m.DateTimeTag,
AssignedToPersonId = m.AssignedToPersonId,
Status = m.Status.ToString(),
NoOfReplys = m.Replys.Count()
}).ToList();
model.ForEach(m => m.AssignedTo = Uow.Persons.GetById(m.AssignedToPersonId).Name);
return model;
}
Note however that this second method is making an additional query to the database for each Ticket object returned in the first query.
I am using Entity Framework as my ORM. It has ComplexTypeAttribute (which is used to annotate POCO's). Properties that are complex types, are always instantiated (using default constructor), regardless of their value; And as a consequence, are always serialized by ServiceStack JsonSerializer (along with their properties).
JSON.NET has an enum called DefaultValueHandling, which can be used in these situations.
Does ServiceStack have something similar?
For example:
class Person
{
string Name { get; set; }
Address Address { get; set; }
}
[ComplexType]
class Address
{
string Street { get; set; }
int Number { get; set; }
int PostalCode { get; set; }
}
When I serialize a person that doesn't have address I get this:
"{ Name: Jim, Address : { Number: 0, PostalCode: 0 } }"
In Json.Net if I set DefaultValueHandling to Ignore, I only get
"{ Name: Jim }"
Yes, here are the different ways you can ignore properties with ServiceStack's JSON and Text serializers.
The serializers also support multiple hooks to customize serialization and deserialization.
The JsConfig class shows all the customizations that are possible.
Please consider changing your value types to nullable data types and set null as default value for any reference type.
class Person
{
string Name { get; set; }
Address Address { get; set; }
}
[ComplexType]
class Address
{
string Street { get; set; }
int? Number { get; set; }
int? PostalCode { get; set; }
}
This should help you get rid of attributes with default values as ServiceStack Text will omit properties with null value. Also observe that 'Age' which is of type int? is omitted from serialized output when it is null. The example also demonstrates serialization using anonymous objects.
Example below:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ServiceStack;
namespace JsonTest
{
class Person
{
public string Name { get; set; }
public string Address { get; set; }
public int? Age { get; set; }
public List<Person> Children { get; set; }
public Person()
{
Children = new List<Person>();
}
}
class Program
{
static void Main(string[] args)
{
var c1 = new Person { Name = "John", Address = "USA", Age = null };
var c2 = new Person { Name = "John", Address = "USA", Age = 12 };
List<Person> children = new List<Person>();
children.Add(c1);
string name = "Jim";
// Uncomment lines below and check - Children attribute is omitted from JSON result
// children = null;
// name = null;
var p1 = new { Name = name, Address = "USA", Age=40, Children = children};
var p2 = new Person { Name = "Jim", Address = "USA" , Age = null};
p2.Children.Add(c2);
Console.WriteLine(p1.ToJson());
Console.WriteLine(p2.ToJson());
Console.ReadLine();
}
}
}
Output:
{"Name":"Jim","Address":"USA","Age":40,"Children":[{"Name":"John","Address":"USA","Children":[]}]}
{"Name":"Jim","Address":"USA","Children":[{"Name":"John","Address":"USA","Age":12,"Children":[]}]}
{"Address":"USA","Age":40}
{"Name":"Jim","Address":"USA","Children":[{"Name":"John","Address":"USA","Age":12,"Children":[]}]}
I need some help...
I have my entity that i have create manually.
public class Project()
{
public Project Data {get;set;}
public string ProjectID { get; set; }
public string AreaID { get; set; }
public string Country { get; set; }
}
Where property "Project" is the the table created by SQLmetal.
I have also created my class, with SQLmetal, wish there have there own entity.
Now i trying to parse between them in the constructor like:
public Project()
{
ProjectID = Data.ProjectID;
AreaID = Data.AreaID;
Country = Data.Country;
}
But when I use
projects.Select(p => new Project { Data = p });
the Data property in the constructor is null.
Any idea why? and how will I solve this the better way?
Yes, because the initializer
var x = new Project { Data = p };
is equivalent to
var x = new Project();
x.Data = p;
The Data property is set AFTER the constructor.
You can solve it by creating a constructor that takes Data as a parameter
public Project(Data data)
{
this.Data = Data;
ProjectID = Data.ProjectID;
AreaID = Data.AreaID;
Country = Data.Country;
}
and call the constructor
projects.Select(p => new Project(p));
In my test vb.net MVC web app, I have this json....
Public Class Person
Public Property Name As String
Public Property Age As Byte
Public Sub New(name As String, age As Byte)
Me.Name = name
Me.Age = age
End Sub
End Class
Function GetPerson() As JsonResult
Dim p As New Person("John Doe", 50)
Return Json(p, JsonRequestBehavior.AllowGet)
End Function
And in Monotouch I've got this...
JsonObject j;
Uri address = new Uri("http://mysite/home/GetPerson");
HttpWebRequest httpReq = (HttpWebRequest)HttpWebRequest.Create (address);
using (HttpWebResponse httpRes = (HttpWebResponse)httpReq.GetResponse ()) {
Stream s = httpRes.GetResponseStream ();
j = (JsonObject)JsonObject.Load (s);
}
And this class...
Public Class Person {
Public string Name { get; set; }
Public byte Age { get; set; }
}
How do I parse the JsonObject j into class of Person? .. I hoped for something like Person p = (Person)j.value;
Thanks!
Mojo
First, I would use int for Age. But assuming a JSON Structure like:
{
"Name" : "John Doe",
"Age" : 100,
}
If you wanted to use the baked in System.Json stuff:
var person = new Person()
var obj = JsonObject.Parse(json);
person.Name = obj["Name"].ToString();
person.Age = (int)obj["Age"];
I would HIGHLY recommend using ServiceStack.Text though, it's a highly optimized extremely fast library for consuming JSON with compatibility with both MonoTouch and Mono for Android...out of the box!
You can check out the the API for consuming JSON with ServiceStack here.
Even if this question is now old, here is the solution I use.
With MonoTouch, you can use .net Json serialization mechanism based on DataContract.
[DataContract]
Public Class Person {
[DataMember]
Public string Name { get; set; }
[DataMember]
Public byte Age { get; set; }
}
and use the DataContractJsonSerializer (found in System.Runtime.Serialization.Json)
Stream stream = httpRes.GetResponseStream ();
DataContractJsonSerializer jsSerializer = new DataContractJsonSerializer(typeof(Person));
Person person = (Person)jsSerializer.ReadObject(stream);
This way, the code is WCF compliant and work flawless on ms.net platform, mono and monotouch.
Given this in my datacontext:
public class EventsForUserID
{
public string eventName { get; set; }
public int eventID { get; set; }
public string eventIdentifier { get; set; }
public DateTime eventOpenDate { get; set; }
public DateTime eventCloseDate { get; set; }
public bool eventDisabled { get; set; }
public EventsForUserID() {}
public EventsForUserID(string pEventName, int pEventID, string pEventIdentifier, DateTime pEventOpenDate, DateTime pEventCloseDate, bool pEventDisabled)
{
this.eventName = pEventName;
this.eventID = pEventID;
this.eventIdentifier = pEventIdentifier;
this.eventOpenDate = pEventOpenDate;
this.eventCloseDate = pEventCloseDate;
this.eventDisabled = pEventDisabled;
}
}
public List<EventsForUserID> GetEventsForUserID(string userID, bool excludeDisabled)
{
var e =
from ex in this.Exhibitors
join ev in this.Events on ex.EventID equals ev.EventID
where ex.UserID.ToString() == userID
select new EventsForUserID (
ev.EventName,
ev.EventID,
ev.EventID + "[::]" + ex.ExhibitorID + "[::]" + ex.AccountDisabled + "[::]" + ev.EventDisabled,
ev.OpenDate.Value,
ev.CloseDate.Value,
ev.EventDisabled
);
if (excludeDisabled) {
e = from ev in e
where ev.eventDisabled != true
select ev;
}
return e.ToList();
}
I get the error:
The member 'LeadsDataContext+EventsForUserID.eventDisabled' has no supported translation to SQL.
on the return.ToList() line.
I've tried all sorts....AsQueryable() etc
I figure it because EventsForUserID is not a true sql table, but then I thought LINQ was for performing queries over many type of object.
Am I missing a cast of some sort.
Many thanks, N
Unfortunately you cannot mix linq-to-objects and linq-to-sql freely in the same query. If you are running the query as a linq-to-sql query, everything must be translated to sql.
Try to split your code into two queries. The first one should retrieve the relevant data from the database using linq-to-sql. The second uses linq-to-objects to do the final filtering/manipulation of data.