I have a DB entity like:-
public class DBThing
{
public int Id { get; set; }
public string Name { get; set; }
}
The Id maps to the DB primary key. I then have a service DTO like:-
public class Thing
{
[IgnoreDataMember]
public int Id { get; set; }
public string Identity { get; set; }
public string Name { get; set; }
}
The Identity field here contains a REST friendly ID like /things/1, made from the DB Id. I had to call it something differennt from Id, because I'm using TranslateTo and it breaks going from Thing to DBThing if the string Id is "" and it tries to map to int Id, such as when a POST occurs.
The problem I have is that my route [Route("/things/{Id}", "PUT")] fails saying it can't find the Id property on Thing. If I remove [IgnoreDataMember] from the class it works fine. I can imagine why this would be (using shared code with ServiceStack serialization internally?) but I can't see how to fix this. I don't want the internal DB numeric Id serialized to the web services if at all possible.
Can anyone help please?
You can use a int? Id which if it's null it doesn't get serialized by default in JSON / JSV Serializers.
Related
I have a WebApi which exposes a Contact field in my database. Currently it has endpoints for Post (create), Put (edit), Get(return whole list), Get(int id) (return specific field).
So the Get(int id) searches my DB for the contact with that id and returns it in JSON. I would like to implement a method by which the user can submit conditions to my first Get function such as:
GET http://urlformyapi.com/api/apiContact/?querystring
Where the query string might be for example:
firstname=phil
And return all the Phil's.
How is best to make this totally searchable for all of my data fields within contact?
public int contactid { get; set; }
[Required]
public string firstname { get; set; }
[Required]
public string lastname { get; set; }
[Required]
public string email { get; set; }
[Required]
public string mobile { get; set; }
public string company { get; set; }
public string position { get; set;}
public string notes { get; set; }
public string image { get; set; }
I could do an initial get of the whole list and then go through each query parameter like:
//where ContactList begins as the entire list of contacts.
if(notes != null){ ContactList = ContactList.Where(x => x.notes == notes).ToList(); }
Thus refining my list until returning it. But I wondered if there was an easier way which was more robust should my data model change/I want to make more fields searchable.
any thoughts?
If you have a lot of similar API methods, you can take a look on OData. Another variant try to use for this purpose Dynamic Linq with custom filter formatting. Otherwise my suggestion is create class which must contains query fields (search fields), for example: notes, ids, etc and then pass this object to API and filter your collections with those search fields and PredicateBuilder. Also good explanation how PredicateBuilder works.
I have the following model:
public class Student
{
public ObjectId Id { get; set; }
public string Name { get; set; }
}
And the this endpoint in my controller:
public IEnumerable<Student> GetAll()
{
MongoCollection<Student> collection = Db.GetCollection<Student>("students");
List<Student> students = collection.AsQueryable().ToList();
return students;
}
The GetAll() endpoint which is exposed to the public, returns a Student which has an Id of type ObjectId, which is not a standart type. I would rather want it to be of type string.
But if I change it to string, I can't use the .ToList(), getting an error like so:
"Cannot deserialize string from BsonType ObjectId"
I know I can solve this using some projections and conversions, but they will add some ugly and noisy code to the CRUD methods.
What is the best way to keep Id in string type exposed to the public and still be able to use the c# driver's api?
The controller should do the conversion. Generally, controllers should communicate using DTOs with the outside world:
public IEnumerable<StudentReadDTO> GetAll()
{
MongoCollection<Student> collection = Db.GetCollection<Student>("students");
List<Student> students = collection.AsQueryable().ToList();
return students.Select(p => AutoMapper.Mapper.DynamicMap<StudentReadDTO>(p));
}
// this DTO should be used for POST and PUT (i.e where there is no id or the id
// is part of the URL) - after all, it doesn't make sense to send the id from the
// client to the server
public class StudentDTO
{
public string Name { get; set; }
}
// this should be used by reading operations, where the id is read from the server
// inheritance in DTOs is a source of confusion and can be painful, but this trivial
// type of inheritance will be fine
public class StudentReadDTO : StudentDTO
{
public string Id { get; set; }
}
This example uses AutoMapper to do a convention-based mapping between Student and StudentDTO, but you do the mapping yourself if you like.
In the database layer, it makes sense to use ObjectId because of its properties.
Although the suggested answer by #mnemosyn using AutoMapper looks like a great solution and a good pattern to handle those kind of cases, in the case of the MongoDB C# driver you have a dedicated solution and can simply put the following attribute and you are done:
public class Student
{
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; }
public string Name { get; set; }
}
(I got this solution from the google group of MongoDB)
Been a long struggle with this one. I'm working with an ASP.NET web API to provide clean and easy HTTP/JSON interaction with a database. I have an entity name Reservation with that looks as following:
// Reservation
public class Reservation
{
public int ID { get; set; } // ID (Primary key)
public int EquipmentID { get; set; } // EquipmentID
public string Username { get; set; } // Username
public DateTime BeginDateTime { get; set; } // BeginDateTime
public int? Duration { get; set; } // Duration
public int? ReservationStateID { get; set; } // ReservationStateID
public DateTime? CheckInDateTime { get; set; } // CheckInDateTime
public string Note { get; set; } // Note
// Foreign keys
public virtual Equipment Equipment { get; set; } // FK_Reservation_EquipmentID
public virtual ReservationState ReservationState { get; set; } //FK_Reservation_ReservationState
}
So far so good. I am running a simple python script to create a new reservation, passing along with the http request a Reservation JSON object. In a previous life I ran the reservation adding code without data validation and returned the Reservation object in the HttpActionResult. What I saw in return was a nice json object:
{u'Username': u'name', u'ReservationStateID': 1, u'Equipment': None, u'EquipmentID': 2, u'BeginDateTime': u'2014-05-31T14:00:00Z', u'Note': u'', u'CheckInDateTime': None, u'Duration': 10800, u'ReservationState': None, u'ID': 51}
I am a little concerned with the foreign keys Equipment and ReservationState being included in the returned object, which may lend to the larger problem, but that in due time.
Now I try to run data validation by gathering the Equipment item referenced by my Reservation.
Equipment equipmentItem = await db.Equipment.FindAsync(newRes.EquipmentID);
Now when I try to perform the same action, using the same data on the same python script the result received is a big scary error:
"The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; charset=utf-8'.", u'StackTrace': None, u'Message': u'An error has occurred.', u'InnerException': {u'ExceptionMessage': u"Self referencing loop detected for property 'Equipment' with type...
I am 99% positive that the foreign keys in place in my database do not create circular references, but alas here I am. Again I want to point out the inclusion of the foreign keys in the "successful" json results. I'm betting if I can be rid of those I can be rid of the self referencing issue. Thanks for the help!
The error was caused by the EF creating proxies for the foreign key objects, the default serializer (DataContractSerializer) errors when serializing with proxies. The solution is to add the following line to the Global.asax.cs file:
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
While #SKall's answer did solve the problem, it didn't solve it throughout the project, just to properties that I gave the IgnoreDataMember attribute.
Mark the references with IgnoreDataMember attribute and let us know if that helped.
[IgnoreDataMember]
public virtual Equipment Equipment { get; set; }
[IgnoreDataMember]
public virtual ReservationState ReservationState { get; set; }
I'm facing a strange error using entityframe work. I have model entity called "UserInfo" and my DB table name is also "UserInfo". However when i'm called the savechanges() in entity frame work. i'm getting a strange error like Invalid object name 'dbo.UserInfoes'.
I searched the entire solution, to see whether i miss typed anything to "UserInfoes" and i didnt find anything. Please help me to solve this issue. How "es" is append along with it?
[Table("UserInfo")]
public class UserInfo
{
public int Id { get; set; }
public string Field1 { get; set; }
public string Field2 { get; set; }
public string Field3 { get; set; }
public string Field4 { get; set; }
public int Field5 { get; set; }
}
You need to disable the Pluralize Table Names for the LINQ to SQL designer.
Here is the steps
http://msdn.microsoft.com/en-us/library/bb384507.aspx
It is probably to do with settings. EF will pluralise table names automatically under some circumstances. The problem may be your entity name: Userinfo -> Userinfoes. It looks like you are using code first so look at your entity settings.
I'm coding in C# using entity framework 5 and I have a model Voucher that is something like this:
public class Voucher
{
public int Id { get; set; }
public int AppId { get; set; }
public virtual App {get; set;}
public int? TradeMemberId { get; set; }
public int FiscalPeriodId { get; set; }
}
I have configured this model as:
ToTable("Voucher", "acc");
So that it is mapped to:
[acc].[voucher]
my App property is from the same database but in another schema:
[prf].[App]
Now when ef tries to query and fill App navigation property it cannot find it in acc schema.how can i mark this property as prf schema as we do for models?any help is appreciated.
If you proper define schema using data annotation. EF should take care of this, I have done this before and never ran into any issues.
[Table("Voucher", Schema = "acc")]
public class Voucher {...}
and
[Table("App", Schema = "prf")]
public class App{...}