I got the result from the collection in MongoDB, the structure is the same as below
[DataContract]
public class Father
{
[BsonId]
[DataMember]
public MongoDB.Bson.ObjectId _id { get; set; }
[DataMember]
public string Id { get; set; }
[DataMember]
public List<Child> childs { get; set; }
}
[DataContract]
public class Child
{
[DataMember]
public string Id { get; set; }
[DataMember]
public int Name { get; set; }
}
When I try this:
List<Father> f = result.ToList();
It calls Element 'Id' does not match any field or property of the class Model.Child
I think it just takes 'Id' as something else.
How can I deal with it? Thank you
You can resolve the issue by adding [BsonIgnoreExtraElements] on top of the class declaration. ObjectId is internally maintained by MongoDB which may not be needed unless you want to get additional information such as timestamp from the object. Hope this helps.
var conventionPack = new ConventionPack { new IgnoreExtraElementsConvention(true) };
ConventionRegistry.Register("IgnoreExtraElements", conventionPack, type => true);
This works just perfectly!
[BsonIgnoreExtraElements] also worked well, but, if you want to add any other ConventionRegistry like CamelCaseElementNameConvention, then, it overrides the Attribute one and the same exception occurs. Not sure if that could also be achieved using some other attribute.
I was using a dynamic list (List) to build a filter and was receiving a similar error. I added these lines to my data class to fix the problem.
[BsonId]
public ObjectId Id { get; set; }
this work for my case: add the attribute
[DataMember]
[BsonElement("songName")]
onto the elements:
[BsonIgnoreExtraElements]
public class Music
{
[BsonId]
[DataMember]
public MongoDB.Bson.ObjectId _id { get; set; }
[DataMember]
public string Id { get; set; }
[DataMember]
[BsonElement("songName")]
public string SongName { get; set; }
[DataMember]
[BsonElement("artistName")]
public string ArtistName { get; set; }}
I faced to same problem.Same error occured at var data = query.ToList();
var collection = db.GetCollection<Product>("Products");
var query =
from e in collection.AsQueryable<Product>()
where e.name == "kalem"
select e;
var data = query.ToList();
and my insert was this:
var collection = db.GetCollection<Product>("Products");
collection.InsertBatch(products);
I solved as below.
ObjectId id = new ObjectId();
var collection = db.GetCollection<Product>("Products");
collection.InsertBatch(products);
id = pr.Id;
and I added id to Product class as below
Product Class
class Product
{
public ObjectId Id { get; set; }
public string name { get; set; }
public string category { get; set; }
public double price { get; set; }
public DateTime enterTime { get; set; }
}
you can use BsonNoId attribute
[DataContract]
[BsonNoId]
public class Child
{
[DataMember]
public string Id { get; set; }
[DataMember]
public int Name { get; set; }
}
just add this in the top of the class
[BsonIgnoreExtraElements]
all you have to do is removing the [DataMember] on the ObjecId attribute and bind the Id to the ObjectId _id.
so your class should look like this :
[DataContract]
public class Father
{
[BsonId]
public MongoDB.Bson.ObjectId _id { get; set; }
[DataMember]
public string Id {
get { return _id.ToString(); }
set { _id = ObjectId.Parse(value); }
}
[DataMember]
public List<Child> childs { get; set; }
}
ps : in your case the child id must be generated manually, if you want it to be an objectId(mongo), you will have do the same trick
finally, to deserialized the object, you should use the newtonsoft.json reference and do like this
Father = JsonConvert.DeserializeObject<Father>(response.Content);
Your Child class should probably specify it inherits Father
public class Child: Father { ... }
Your Father class should probably add known type attribute (for WCF ).
[DataContract]
[KnownType(typeof(Child))]
public class Father
If this is a MongoCollection("fathers") that you save / fetch through, then you may need to register a class map for each expected child type.
if (!BsonClassMap.IsClassMapRegistered(typeof(Child)))
{
BsonClassMap.RegisterClassMap<Child>(
cm => { cm.AutoMap(); });
}
As #alexjamesbrown mentioned, you are not required to name the id field on your poco object '_id'.
The idea with inheritance is to inherit. So using the Father's "id" field (whatever it is named) should suffice. It's not clear why your Father class has both Id and _id properties. One of them is probably not necessary.
Related
I can't find annotation for MongoDb, what can in .Net Core model modify collection name. In SQL database it will be [Table("all_sessions")].
My model name and collection name are different. I have not change model or collection name.
public class Session
{
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
[BsonElement("_id")]
public string Id { get; set; }
[BsonElement("expires")]
public string Expires { get; set; }
[BsonElement("session")]
public string Session { get; set; }
}
My collection name is all_sessions.
I expect get working Session model with all_sessions collection.
So time ago i was fancing similar issue and i've created my own implementation of that pattern.
So first part is to create custom attribute:
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
public class BsonCollectionAttribute : Attribute
{
private string _collectionName;
public BsonCollectionAttribute(string collectionName)
{
_collectionName = collectionName;
}
public string CollectionName => _collectionName;
}
Second part is to obtain the value of this attribute with reflection
private static string GetCollectionName()
{
return (typeof(T).GetCustomAttributes(typeof(BsonCollectionAttribute), true).FirstOrDefault()
as BsonCollectionAttribute).CollectionName;
}
I'am doing that in repository class, so example method from mthat class looks like that:
public async Task InsertOne(T model)
{
var collectionName = GetCollectionName();
var collection = Database.GetCollection<T>(collectionName);
await collection.InsertOneAsync(model);
}
In the end my model looks like:
[BsonCollection("Users")]
public class User
{
[BsonId]
[BsonElement("id")]
[BsonRepresentation(BsonType.String)]
public Guid Id { get; set; }
[BsonElement("name")]
public string Name { get; set; }
[BsonElement("email")]
public string Email { get; set; }
[BsonElement("password")]
public string Password { get; set; }
Hope that i've helped ;)
I have a little problem when I try to save an item in my DB using EntityFramework.
My classes looks like:
public partial class Site
{
public int Id { get; set; }
public string Name { get; set; }
public string LongName { get; set; }
public string Adress { get; set; }
public City City { get; set; }
public Country Country { get; set; }
public string VATNumber { get; set; }
}
public class Country
{
public int CountryId { get; set; }
public string Name { get; set; }
public string IsoCode { get; set; }
}
And when I try to create a new site in my controller it works, but when I try to add a link to an existing Country :
if (SiteProvider.GetSiteByName(Site.Name) == null)
{
Site.Country = CountryProvider.GetCountryById(1);//it's working, i see the link to the right country
SiteProvider.Create(Site);
}
public static void Create(Site Site)
{
using (MyDBContext Context = new MyDBContext())
{
Context.Site.Add(Site);
Context.SaveChanges(); //here is the problem
}
}
I got this error:
SqlException: Cannot insert explicit value for identity column in
table 'Country' when IDENTITY_INSERT is set to OFF
Thanks in advance for your help.
Add CountryId property to Site class and when adding a new Site set CountryId instead of Country property
public int CountryId { get; set; }
[ForeignKey("CountryId")]
public Country Country{ get; set; }
You have a slight issue with your use of contexts here. You have used one DBContext instance to load the country (where this country object will be tracked) and then a second DBContext to save the site (where the first country object is a property).
It is preferable to perform all your operations for a single unit of work by using one DB context (that would be shared between your classes) and the responsibility for disposing of it to be handled outside your repository layer.
Here is a simplified version of my model:
public class User {
public int UserID { get; set; }
public string FirstName { get; set; }
public virtual ICollection<Recipe> Recipes { get; set; }
}
public class Recipe {
public int RecipeID { get; set; }
public string RecipeName { get; set; }
public int UserID { get; set; }
public virtual User User { get; set; }
}
I have a controller that I'd like to return a User as well as some summary information about their recipes. The scaffolded controller code looks like this:
var user = await _context.Users.SingleOrDefaultAsync(m => m.UserID == id);
It works fine. Now I try to add the Recipes, and it breaks:
var user = await _context.Users.Include(u => u.Recipes).SingleOrDefaultAsync(m => m.UserID == id);
My web browser starts to render the JSON, and it flickers and I get a message in the browser saying the connection has been reset.
My Theory - I believe that the parent (User) renders, which exposes the child (Recipe) which contains a reference to the parent (User), which contains a collection of the child (Recipe) and so on which is causing an infinite loop. Here's why I think this is happening:
The Visual Studio debugger allows me to navigate the properties in that way infinitely.
If I comment out the Recipe.User property, it works fine.
What I've tried
I tried to just include the data from Recipe that I need using Entity Framework projection (I'm attempting to not include Recipe.User). I tried to only include Recipe.RecipeName... but when I try to use projection to create an anonymous type like this:
var user = await _context.Users.Include(u => u.Recipes.Select(r => new { r.RecipeName })).SingleOrDefaultAsync(m => m.UserID == id);
I receive this error:
InvalidOperationException: The property expression 'u => {from Recipe r in u.Recipes select new <>f__AnonymousType1`1(RecipeName = [r].RecipeName)}' is not valid. The expression should represent a property access: 't => t.MyProperty'.
What is the solution? Can I project with different syntax? Am I going about this all wrong?
Consider using POCOs for serialization rather than doubly-linked entity classes:
public class UserPOCO {
public int UserID { get; set; }
public string FirstName { get; set; }
public ICollection<RecipePOCO> Recipes { get; set; }
}
public class RecipePOCO {
public int RecipeID { get; set; }
public string RecipeName { get; set; }
public int UserID { get; set; }
}
Copy the entity contents to the corresponding POCO and then return those POCO objects as the JSON result. The removal of the User property via usage of the RecipePOCO class will remove the circular reference.
I can propose you 3 options.
U sing [JsonIgnore] on property, but it will work on every use of Recipe class, so when you would like to just return Recipe class you won't have User in it.
public class Recipe {
public int RecipeID { get; set; }
public string RecipeName { get; set; }
public int UserID { get; set; }
[JsonIgnore]
public virtual User User { get; set; }
}
You can this solution to stop reference loop in all jsons https://stackoverflow.com/a/42522643/3355459
Last option is to create class (ViewModel) that will only have properties that you want send to the browser, and map your result to it. It is propably best from security reason.
Using Microsoft.Azure.Mobile.Server EntityData, I have a class that looks like
public abstract class BaseItem : EntityData
{
public string Owner { get; set; }
public string Text { get; set; }
}
How do I ensure that the Owner and Text are indexed?
Update. I think I can add [Index(IsClustered = false)]
Use standard Entity Framework semantics.
public class BaseItem : EntityData
{
[Required]
[Index]
public string Owner { get; set; }
}
For more information, see http://www.entityframeworktutorial.net/code-first/dataannotation-in-code-first.aspx
Quite new with LINQ. I am wondering how I would be able to achieve this.
I have the following table classes defined:
public partial class Cars
{
public long ID { get; set; }
public string CarName { get; set; }
public long CarModelID { get; set; }
public virtual CarModel CarModel { get; set; }
}
public partial class CarModel
{
public long ID { get; set; }
public string ModelName { get; set; }
public long StockID { get; set; }
}
public partial class Stock
{
public long ID { get; set; }
public string StockName { get; set; }
}
There's also a defined extension for the class Cars (Cars.extension.cs):
public partial class Cars
{
public List<Stock> StockList { get; set; }
}
I am trying to get all the Cars, CarModel and (List of) Stocks via the following query:
var query = (from cars in Context.Cars.Include("CarModel").Include("StockList")
select cars).FirstOrDefault();
It is giving me an error:
"A Specified Include Path is not Valid. The Entity Type Cars does not declare a Navigation Property with the name 'StockList'"
How would I be constructing my LINQ query such it would include possibly the list of Stocks based on a CarModel based off Cars?
The Include method is adhering to FluentAPI principles, that means further Include() calls are still in the context of the parent entity (Cars) and not in the previously included CarModel.
What you need is:
Cars.Include("CarModel.StockList")
Or
Cars.Include(x => x.CarModel.StockList)