4

I'm using WCF Data Services for a RESTful API that returns a JSON response.

consider this object:

[Table("person")]
public class Person
{
    [Column("dob", TypeName = "datetime")]
    public DateTime DateOfBirth { get; set; }

    [NotMapped]
    public int Age
    {
        get { return CalculateAge(); }
        set { }
    }
}

WCF does not treat this object as I would expect. My service request completely ignores the Age property in the serialization of the Person object.

I've been using a workaround where I map the Age property to a dummy database column and I create a setter that does nothing. What an ugly hack! Is there a better way to have a DataService return a property that is not mapped to a database column?

codemonkey
  • 1,213
  • 2
  • 14
  • 31

4 Answers4

4

After much research, and no evidence to the contrary on stackoverflow, i'm going to go ahead and say the answer is: No. A WCF DataService with entities mapped using EntityFramework 4 can NOT return unmapped properties.

The ugly hack i've been using is this one, which requires you to acutally make a field in the database that just never gets read.

[Table("person")]
public class Person
{
    [Column("dob", TypeName = "datetime")]
    public DateTime DateOfBirth { get; set; }

    [Column("dummy1", TypeName = "int")]
    public int Age
    {
        get { return CalculateAge(); }
        set { }
    }
}
codemonkey
  • 1,213
  • 2
  • 14
  • 31
  • I came to the same conclusion. Entity Framework [does not expose](http://social.msdn.microsoft.com/Forums/vi-VN/adodotnetdataservices/thread/e76c36b3-c8cb-4de8-ae4c-d214406e49b6) "NotMapped" properties in the Conceptual Model, so WCF Data Services never sees them. Suggested workarounds are: 1) add a redundant column in the database; 2) add a dummy column in the database and compute its value in code; 3) calculate the property on the client-side (all clients); 4) use [Feed Customization](http://msdn.microsoft.com/en-us/library/ee373839.aspx), unfortunately only for ATOM, not supported for JSON. – Fernando Correia May 15 '12 at 18:17
2

Here's what I used in those situations, similar to what is stated by tyrongower:

NOTE: this works with WCF and REST WCF as well as with JSON

[DataContract]
public class Submission
{
    [NotMapped]
    [DataMember]
    public string Location
    {
        get { return ""; }
        set { }
    }
}
AlexVPerl
  • 7,652
  • 8
  • 51
  • 83
1

You may need to use the System.Runtime.Serialization attributes as these are what WCF will look at.

Not sure if you can have logic in your data contracts though.

[Table("person")]
[DataContract]
public class Person
{
    [Column("dob", TypeName = "datetime")]
    [DataMember]
    public DateTime DateOfBirth { get; set; }

    [NotMapped]
    [DataMember]
    public int Age
    {
        get { return CalculateAge(); }
    }
}

EDIT:

May need private setter (How do you configure a get-only property for a Silverlight-enabled WCF service)

Community
  • 1
  • 1
TheRealTy
  • 2,409
  • 3
  • 22
  • 32
  • Looks so promising, but alas it doesn't work. The Age property is still missing from my JSON object in the response. – codemonkey Feb 03 '12 at 01:05
  • I had tried that as well and it doesn't work either. The linked question you shared is different in that their serialized objects are not mapped to the database using EntityFramework. – codemonkey Feb 03 '12 at 17:34
0

I too hit this snag and decided to use extension methods. For example:

public static class PersonExtensions
{
    public static int GetAge(this Person person)
    {
        // your CalculateAge logic (simplified)
        return (DateTime.Now - person.DateOfBirth).TotalDays / 365;
    }
}

Then, in your DataServices consumer, you can do:

person.GetAge()

Yeah, it's not as nice as person.Age, but you're also not adding unnecessary database columns.

Update:

Another alternative is to extend the Person class contained in the service reference. You can do this by creating a partial Person class with the same namespace as the service reference Person class. For example:

public partial class Person
{
    public string int Age
    {
        get { return (DateTime.Now - this.DateOfBirth).TotalDays / 365; }
    }
}

Then the DataServices Person model will have the Age property!

Pakman
  • 2,170
  • 3
  • 23
  • 41
  • Very cool workarounds. I like them, but have not tried them out. Since my last post i've refactored the code to no longer use DataService and just use the vanilla WCF services which has provided me more flexibility. But also forced me to create my own search methods with paging and sorting and querying. – codemonkey Apr 03 '12 at 18:24