Querying MongoDb Data based on BsonId in C# - c#

I'm working my way through a Plural Sight course to get some insight in MongoDB. It's one of the basic courses on the 'path' and it seems to have been made pre 2.0. As such I'm having some trouble understanding some of the subjects the tutor is going through.
I was hoping to see if someone could clarify how to Find any object based on their BsonID?
This is my object:
public class Patient
{
[BsonElement("_id")]
[BsonId]
public string Name { get; set; }
public ICollection<Ailment> Ailments { get; set; }
public ICollection<Medication> Medications { get; set; }
}
And this is how I'm trying to query it:
public HttpResponseMessage Get(int id)
{
var patient = _patients.Find(pat => pat._id == id).ToList();
if(patient == null)
{
return Request.CreateErrorResponse(HttpStatusCode.NotFound, "Patient Not Found..");
}
return Request.CreateResponse(HttpStatusCode.OK, patient);
}
This syntax doesn't allow me to build the project as there isn't a property with the name _id. I've also attempted to have an actual property ID, but that seems to create some sort of a problem when building (most likely since I already have an ID in it, created by BsonID).
I'm really sorry if this question has been asked before, but I seriously couldn't find any help on the subject. It seems like there should be a lot of resources on it (ie. us newbies should be able to get some good sources back when searching for something like "c# querying mongodb find on BsonId").
I fully understand if this is going to be down voted, but I'd really love it if someone with some time over could help me out here.

Your are putting together a C# query which doesn't know about the MongoDB mapping you specify in the attribute [BsonElement("_id")] on your POCO.
What you want is
var patient = _patients.Find(pat => pat.Name == id).FirstOrDefault();
EDIT (for clarification):
The MongoDB C# driver will dissect the filter expression pat => pat.Name == id and based on the attributes on your POCO it will create a MongoDB query for you that uses the "_id" field.

The C# driver for Mongo requires an id field (some way to uniquely identify your documents). This can either be determined by convention or specified explicitly by you.
By convention, if you have a class with a public member of type ObjectId named Id then the C# driver for Mongo will assume this is your id and it will be mapped to a field called _id in your Mongo collection.
For example:
public class Widget
{
public ObjectId Id { get; set; }
public string Foo { get; set; }
}
If you don't want to go with the convention for some reason (for example if you have a natural key that you'd rather use) then you can use the BsonId attribute to tell the Mongo driver that you want to use some other field/type as your Id.
For example:
public class Widget
{
[BsonId]
public ObjectId WidgetId { get; set; }
public string Foo { get; set; }
}
Or using a type other than ObjectID:
public class Widget
{
[BsonId(IdGenerator=typeof(StringObjectIdGenerator))]
public string WidgetId { get; set; }
public string Foo { get; set; }
}

Related

Type safe keys with Entity Framework model

This is my perfect idea of day: Strong typed ids in Entity Framework.
Motivation:
Comparing ModelTypeA.ID and ModelTypeB.ID is (at least almost) always an error. Why not compiletime handle it?
If you are using example per request DbContext its easy to implement get directly model from id. "id.Value.ProductNumber"
Code will be more self declarative.
They are just naturally typed so why not?
Ok here is my implementation. I hope its pretty self declarative what I mean.
//Optional interface may be handy on some scenarios
public interface Identifiable<T> where T : class, Identifiable<T>
{
DbId<T> ID { get; set; }
}
public class TestModel1 : Identifiable<TestModel1>
{
[Key]
public DbId<TestModel1> ID { get; set; }
public string Data1 { get; set; }
}
public class TestModel2 : Identifiable<TestModel2>
{
[Key]
public DbId<TestModel2> ID { get; set; }
public string Data2 { get; set; }
public DbId<TestModel1> TestModel1ID { get; set; }
public virtual TestModel1 TestModel1 { get; set; }
}
[Serializable]
public class DbId<T> where T : class
{
public int ID { get; set; }
public static implicit operator DbId<T>(int id)
{
var c = new DbId<T>() { ID = id };
return c;
}
public static implicit operator int (DbId<T> id)
{
return id.ID;
}
}
When creating migration its jus complain that there is no key. When trying to set key on fluent api it give more precious error: The property 'ID' cannot be used as a key property on the entity 'MyNs.Models.TestModel1' because the property type is not a valid key type. Only scalar types, string and byte[] are supported key types.
Ok understood key cannot be any type but data of my type is just one int witch even has implicit conversions. Inheriting int in this situation is very tempting but like we know its impossible.
Primary question: How to finish this and tell to EF that converting my DbId to int and back is not rocket science.
Secondary question: Is this good idea? Why? Do you suggest feature request if this is not currently possible?
I believe I understand your goal: your aim is to encapsulate the primary key of each model such that primary keys of two different models cannot be compared directly. So, for example, you would want to avoid the comparison Customer.ID == Order.ID at compile time.
However, in your code example, the implicit operator for int <-> DbId<T> works against your goal because this code compiles:
var model1 = new TestModel1() {ID = 1};
var model2 = new TestModel2() {ID = 2};
Console.WriteLine(model1.ID == model2.ID);
So, if I follow your reasoning, it would not work even if EF6+ allowed [Key] on a class (other than string.)
Getting back to basics, if you believe the name ID is too ambiguous, why not follow the Entity Framework Primary Key Convention of class name followed by "ID"?
Example:
public class Customer
{
// [Key] is implicit by convention
public int CustomerID { get; set; }
public string Name { get; set; }
}
public class Order
{
// [Key] is implicit by convention
public int OrderID { get; set; }
public DateTime SubmittedDate { get; set; }
// [ForeignKey("Customer")] is implicit by convention
public int CustomerID{ get; set; }
public virtual Customer Customer { get; set; }
}
This naming convention (along with plain ID) is the convention I see the most in Entity Framework code. So, it has the major benefit of allowing other people to step in and seamlessly acclimate and maintain your code (a benefit that we tinkerers are all guilty of overlooking sometimes!)
Looking at your motivations...
Comparing ModelTypeA.ID and ModelTypeB.ID is (at least almost) always an error.
Are you solving a problem that isn't actually a problem? How often do programmers really screw up Order.CustomerID == Customer.CustomerID?
Code will be more self declarative.
Up to debate? If I spot DbId<Customer> id = Customer.ID in someone's code, is it really more declarative than int id = Customer.CustomerID?
That said, I applaud your effort! Solving problems is what we programmers love to do. Good luck!

$orderBy with duplicate property in odata v4

I have the following models:
public class Field
{
public string Name { get; set; }
public int Order { get; set; }
public int FieldGroupId { get; set; }
}
public class FieldGroup
{
public string Name { get; set; }
public int Order { get; set; }
public virtual ICollection<Field> Field { get; set; }
}
And what I am want to do is a query where I can order first by the group and then by the field, like:
http://localhost:44300/API/odata/IntFieldSet?$count=true&$expand=FieldGroup&$orderby=FieldGroup/Order,Order
However, when I try it I receive the following error:
Duplicate property named 'Order' is not supported in '$orderby'.
Although they have the same name, they are not the same field. If I try order by fields with different names or only one of those per time, it works. Ex:
$orderby=FieldGroup/Order,Name || $orderby=FieldGroup/Order || $orderby=Order
It used to work on odata v3 but not anymore that I am using odata v4.
Anyone have faced this problem before. Can you help me to find out a solution?
Thanks in advance.
I have the same issue using WebAPI OData 5.6 and 5.7.
However they say they fixed it in version WebAPI Odata 5.7: https://github.com/OData/WebApi/issues/376
Will wait for publication of the update.
It is fixed now.
The correct query should look something like:
http://localhost:44300/API/odata/IntFieldSet?$count=true&$expand=FieldGroup&$orderby=FieldGroup/Order asc,Order desc
It will rougly be translate to:
.OrderBy(x => x.FieldGroup.Order).ThenByDescending(x => x.Order);
Here's an example from odata.org:
http://services.odata.org/TripPinRESTierService/Airports?$orderby=Name%20asc,%20Location/Address%20desc

How to map a class properties in dynamodb without using attribute in .net

I am very new in dynamodb. I am following http://www.rkconsulting.com/blog/persistence-model-framework-with-aws-dynamodb
step by step tutorial for connecting and CRUD operation in dynamodb and it`s works fine.
In that tutorial they using attribute mapping for map class properties
[DynamoDBTable("Dinosaur")]
public class Dinosaur
{
[DynamoDBHashKey]
public string Id { get; set; }
[DynamoDBProperty(AttributeName = "Name")]
public string Name { get; set; }
[DynamoDBProperty(AttributeName = "HeightMetres")]
public double HeightMetres { get; set; }
[DynamoDBProperty(AttributeName = "WeightKG")]
public double WeightKg { get; set; }
[DynamoDBProperty(AttributeName = "Age")]
public int Age { get; set; }
[DynamoDBProperty(AttributeName = "Characteristics")]
public List<string> Characteristics { get; set; }
[DynamoDBProperty(AttributeName = "Photo", Converter = typeof(ImageConverter))]
public Image Photo { get; set; }
[DynamoDBIgnore]
public int IgnoreMe { get; set; }
}
My question is there any way to map class properties without using attribute ?
like as mongoDb
public class Employee
{
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; }
}
we can write this in this way in a separate class
BsonClassMap.RegisterClassMap<Employee>(cm => {
cm.AutoMap();
cm.IdMemberMap.SetRepresentation(BsonType.ObjectId);
});
Is it possible in dynamodb ?
In the latest version of the .NET SDK you don't have to put in the attribute tags, it will see all read/write properties and upload the attributes as the same name. You would only have to use the [DynamoDBProperty(...)] if you want the attribute name in DynamoDB to be something other than the .NET object name.
So in your case you could simply remove that attribute for all properties except photo (which needs the converter, you could remove the AttributeName part of it) and WeightKg (because the capitalization is different) and you would get the same result.
I see this is a little bit older question now, so it may not have been that way in older versions (not sure) but I'm using 3.3.0.0 of the SDK and it does work that way. You have probably moved on but answering for others that may come upon this thread as I did...
There is no way, the default "strongly typed" client relies on attributes.
If you have time to do the plumbing yourself - there is nothing stopping your from doing your own implementation of the POC to Dynamo mapping though. Amazon client api (AWSSDK.DynamoDBv2) exposes the raw class AmazonDynamoDBClient which handles all the API calls and the DynamoDBConext is just implementation of IDynamoDBContext interface - which exposes all the "strongly typed" operations. So you can make your own implementation and take different mapping approach in it.
Also you can make a feature request for this:
https://github.com/aws/aws-sdk-net/issues

ValueInjector not mapping property

I'm having trouble trying to get ValueInjector to map my objects correctly. This is the code I am using for the mapping:
public IEnumerable<CategoryDTO> FindCategories(IList<object[]> criteria)
{
IEnumerable<Category> categories = _categoryRepo.Find(criteria);
IEnumerable<CategoryDTO> categoriesDto = Mapper.Map<IEnumerable<Category>, IEnumerable<CategoryDTO>>(categories);
return categoriesDto;
}
the variable categories contains a property:
IEnumerable<Standard> Standards
This property contains two Standard objects in the instance I'm calling on. The problem is when I map from my Category to my CategoryDTO. CategoryDTO is defined as this:
public class CategoryDTO : AuditableDTO
{
public Guid CategoryId { get; set; }
public string Name { get; set; }
public string MachineName { get; set; }
public string Description { get; set; }
public IEnumerable<StandardDTO> Standards { get; set; }
}
After the mapping statement is run, and I investigate the contents of categoriesDto.Standards, I can see that it is null. I would have expected my Standards to have mapped, but I'm sure I'm missing something with ValueInjector. Probably something along the lines of telling it how to map Standard to StandardDTO. Any thoughts?
EDIT: I need to clarify, I'm using this http://valueinjecter.codeplex.com/wikipage?title=Automapper%20Simulation&referringTitle=Home
EDIT 2: Digging deeper, I can see that my Iesi.Collections.HashedSet is causing the issue. Categorys' Standards property are typed as Iesi.Collections.ISet, this is turned into the HashedSet. So I guess my real question is how do I check the property for that type and how can I map?
My guess would be that the Mapper.Map doesn't know to map one level deeper than the IEnumerable. Have you tried looping though the collection, mapping it at the Category, CategoryDTO level vs the IEnumerable level?

EF Code First 4.1: "Multiple Inheritence" (Is A) Question

I am trying to model a sort of "multiple inheritence" relationship with EF 4.1 Code First. Here is an example what I am trying to do.
Let's say I am attempting to model the way a user interacts with my application using a "User" object. This, being the base class, is used to describe the current user when they aren't doing anything in particular (such as visiting the homepage). It may look like this:
public class User
{
public Guid ID { get; set; } // Just use the forms authentication user ID
public string FirstName { get; set; }
public string LastName { get; set; }
}
Now, if I want to create a representation of that same user but in a different portion of the site, say, as a shopper, it may look like this:
public class Shopper : User
{
public virtual ICollection<Orders> Orders { get; set; }
}
And so on, and so forth. When I go to insert a Shopper that has a pre-existing User entry, it throws an exception because the PK is already taken in the User table.
Is there any way to model this (IsA) relationship with EF Code First? Or am I going to be stuck with something like this?
public class Shopper
{
public Guid UserID { get; set; }
public virtual User User { get; set; }
public virtual ICollection<Order> Orders { get; set; }
public string FirstName
{
get { return User.FirstName; }
set { User.FirstName = value; }
}
// yada, yada, yada...
}
I would like to stick with Code First and model the relationships right in my DbContext, but I can't figure out quite how to do something like this. Thanks!
EDIT:
So, I am trying to do something like this:
public void SomeMethod ()
{
var UserID = Guid.NewGuid ();
var MyUser = new User () { ID = UserID };
SaveUserToDatabase (MyUser);
var ShopperRepresentation = GetUserAsShopper (UserID);
// Do stuff.
}
Basically like using object-oriented roles, I guess. I want to use the same PK for every represenation of that user, but store all of their basic information in a base class called User. I know this is possible if I write my own SQL, of course, but I want to see if EF Code First can do it, too.
Yes, you can do it the way you describe in your first two code examples.
I think you just need to define a mapping, which you'll want to do in your OnModelCreating function of your DataContext in addition to having your classes set up right. How you do it depends on what mapping scheme you're using. I went for Table-Per-Type (TPT) in my most recent project, so I had something like this:
modelBuilder.Entity<User>().ToTable("Users");
modelBuilder.Entity<Shopper>().ToTable("Shoppers");
modelBuilder.Entity<OtherUser>().ToTable("OtherUsers");
Let me know if that doesn't work for you and I'll see what I can do.
Edit:
Having seen your clarification below, I can't think of a way to do that. You'd have to keep each objects stored separately (having EF treat a Shopper as just a Shopper, not a Shopper and a User), even though they share common data. That could lead to data mismatches (if, say, Shopper got its LastName updated but User didn't). I think you might be better off going with something like:
public class User
{
public virtual Guid ID { get; set; }
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
public virtual ShopperInfo { get; set; }
}
public class ShopperInfo
{
public virtual ICollection<Order> Orders { get; set; }
}
and then when you need to treat User as a Shopper, you just access the ShopperInfo (and if its not there, you create it). EF will be able to properly set that up for you no problem.
Though if you're going to have a lot of types of users, that might get cumbersome. Just a suggestion though - I think its a bit cleaner.

Categories