What's the best way to adapt different data types between insert/select from MongoDB? - mongodb-.net-driver

I think I am missing a simple solution here. When I run a select (using Linq-style on IQueryable) that returns IQueryable, I may want MyClass to return differently-formatted key/values than I will use in my insert.
Consider as example the below UploadFile class and note properties id and Filetimestamp. When I SET Filetimestamp I want it stored as DateTime, but when I RETRIEVE IQueryable I would like to:
See Filetimestamp returned as String
OR
See a separate property returned as String reflecting Filetimestamp.toString(). This property doesn't have a corresponding key in the database; it's just a decoration of a real key/value from BSON.
Thinking #1 was unlikely, I pursued #2 by adding a get-only field Filetimestamp_str that returns Filetimestamp.toString(). When I select, behavior is as expected. When I insert, I see failures.
I could create a decorator class that I use for gets and all would work - but am I missing something more fundamental and simple here?
public class UploadFile : IUploadFile
{
public Object _id { get; set; }
public String Filepath { get; set; }
public String Filename { get; set; }
public String Filetype { get; set; }
public String Fileauthor { get; set; }
public DateTime Filetimestamp { get; set; }
public Object FileID { get; set; }
// these keys are not in DB
public String Filetimestamp_str { get { return Filetimestamp.ToString(); } }
public String _id_str { get { return _id.ToString(); } }
}

You could create a BsonClassMap, specifying which properties should (not) be serialized. See the Serialization Tutorial. However, according to that tutorial, a read-only property should not be automapped, so I should not expect errors on the insert.

Related

Add calculated value to OData result

I'm trying to add some info to the data result whether the user has read or write access to the entity.
Lets assume I have this entity:
public class Foo
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Access> AccessRights { get; set; }
}
Where AccessRights holds the user id and if they have read/write access.
Currently I just $expand AccessRights and calculate if the user has read/write access in the frontend. However I'd like this calculated property to be added to the result.
Example json result:
{
id: 1,
name: "foo",
hasReadAccess: true,
hasWriteAccess: true
}
Is it possible to do this? Keep in mind that HasRead/WriteAccess doesn't exist on the model nor should it.
You need to split your model in two: a data access model (what you get from the data access layer) and a data transfer model (what you send as a response).
Assuming your current Foo class as the data access model, you simply need to define another class FooResponse (or whatever name suits you) as follows.
public class FooResponse
{
public int Id { get; set; }
public string Name { get; set; }
public bool HasReadAccess { get; set; }
public bool HasWriteAccess { get; set; }
}
Then define a transformation function that maps from Foo instances to FooResponse instances. AutoMapper is a good tool for the job.

Store same fields twice during serialization

I have a very simple POCO like:
public class Sample()
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
I'd like to use a custom Attribute like [AdditionalLowerField] as below
public class Sample()
{
public ObjectId Id { get; set; }
public string FirstName { get; set; }
[AdditionalLowerField]
public string LastName { get; set; }
}
so that in MongoDB LastName field is serialized twice, with an additional lowered case field like this:
{
_id : ......,
FirstName : "Mario",
LastName : "Special Case",
LastNameLower : "special case"
}
I'm trying to figure this out from doc http://docs.mongodb.org/ecosystem/tutorial/serialize-documents-with-the-csharp-driver/#write-a-custom-attribute but it's not so complete and I don't find good examples for this scenario.
Update: I know that an additional read-only Property can be used together with a [BsonElement] attribute to store its value in MongoDB during serialization and avoid to get it back during deserialization like described in opt-in paragraph:
[BsonElement]
public string LastNameLower
{
get { return LastName.ToLowerInvariant(); }
}
But I'd like to avoid creation of additional properties if possible.
Does anybody have experience on this scenario?
Thanks

Error deserializing JSON to a class with IEnumerable

I need to return a collection with nested optional collections from my WebAPI and convert it back to objects in my Web UI, however I'm getting the following error:
Cannot create and populate list type System.Linq.IQueryable`1[MyNamespace.MyClass].
I'm using Json.Net.
Here is a sample of my code:
public class ClassA
{
public Int64 Id { get; set; }
public String Description { get; set; }
public IEnumerable<ClassB> { get; set; }
}
public class ClassB
{
public Int64 Id { get; set; }
public String Description { get; set; }
}
I've saw some questions here in stackoverflow, but I don't have access to serialization options (it is handled internally by our library).
UPDATE
I've forgot to mention that ClassA is returned as an IQueryable in my Web API.
Changing the return type of my Web API method to IEnumerable instead of IQueryable solved the problem.

MVC3 Optional parameters

This is a follow up to this:
What does MVC3 do with C# Optional Parameters?
I have an action with the following signature:
public ViewResult Show(int Id, PublishingErrorSummary pubErrors=null, String title=null)
On requesting server/show/1 pubErrors is not null, but title is null. How is it possible? These are just two objects but string somehow manages to become null. Where can I fix this?
Edit: class definition added
public class PublishingErrorSummary
{
public List<string> StepOneErrors { get; set; }
public List<string> StepTwoErrors { get; set; }
public List<string> StepThreeErrors { get; set; }
public List<string> StepFourErrors { get; set; }
}
PublishingErrorSummary is a complex object. The default model binder always initializes complex objects. It doesn't really make sense to set its default value to null. Same stands for the title parameter. Strings are reference types and their default value will be null anyway if no request parameter title is sent.

About asp.net mvc model binding and its parameters

Here is view models
public class ArticleViewModel
{
public string ID { get; set; }
public string Title{ get; set; }
public string Body { get; set; }
public List<BETag> TagsList { get; set; }
}
public class BETag
{
public string ID { get; set; }
public string Name { get; set; }
}
An action
[HttpPost, AuthorizeEx]
public ActionResult AddArticle(ArticleViewModel articleViewModel)
{
//articleViewModel.Tags.Count == 0
//Request.Form["TagsList"] == "tag1, tag2..."
}
and a part of AddArticle.cshtml
#Html.TextAreaFor(m => m.TagsList )
My question is why articleViewModel.Tags.Count is equal 0, but
Request.Form["TagsList"] is equal "tag1, tag2..."? How to bind ArticleViewModel properly?
Lists don't work that way in MVC. You need to use something like EditorFor(m => m.TagsList) and then you need to create a BETag EditorTemplate. But that's only part of the problem, and really won't work for you either.
What you really want is just a simple string that takes your list of tags, such as
public string TagListString {get;set;}
Then, in your controller, you parse the string and extract all your tags, then add them to the TagsList.
var tags = TagListString.Split(' '); // assumes only single space between tags,
// you should add more filtering to make sure
foreach(var tag in tags) {
TagList.Add(new BETag() { Name = tag });
}
MVC works with single items, not complex types. There is some built-in processing to breakdown complex types in some cases, and to automatically iterate over collections, but those don't work in your case because you want to edit all the items in a single field. So your only option is to parse the field in the post method and put the data where you want it.

Resources