I have the following class structure:
public class Parent {
public List<Child> Children { get; set; }
}
public class Child {
}
public class MyParent : Parent {
}
public class MyChild : Child {
}
I create an instance of MyParent, and I add an instance of MyChild to Children.
When I save MyParent to Mongo, want the type to be of 'Parent', and the type of each child to 'Child'. Instead, it sets the type to MyParent and each child to MyChild, and then another program that doesn't know about MyParent and MyChild can't handle it.
I tried adding [BsonDiscriminator("Parent")] above 'MyParent', and the same with MyChild, which correctly set the '_t' value, but then I got an ambiguous class error in my own application on deserialization.
Any ideas? Thanks,
You can't have the same discriminator for two classes (that's why you were getting an error message about ambiguous discriminators).
This is a really odd situation to be in, wouldn't it be better to make your class structure match what you are doing in other languages?
In any case, you can resolve the ambiguity by using a different discriminator for the base class (which presumably will never appear in your database...).
[BsonDiscriminator("BaseParent")]
public class Parent
{
public ObjectId Id { get; set; }
public List<Child> Children { get; set; }
}
[BsonDiscriminator("BaseChild")]
public class Child
{
}
[BsonDiscriminator("Parent")]
public class MyParent : Parent
{
}
[BsonDiscriminator("Child")]
public class MyChild : Child
{
}
Related
I am using EF 6. I have a table in db for which the auto-generated class looks like this:
public partial class tblPreparation
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public tblPreparation()
{
this.tblPreparationItem = new HashSet<tblPreparationItem>();
}
public int id { get; set; }
public string name { get; set; }
public System.DateTime date { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<tblPreparationItem> tblPreparationItem { get; set; }
}
In my code, I want this class to extend another class EntityObject, which is in the namespace System.Data.Entity.Core.Objects.DataClasses (and implement another interface). So I created wrote this partial class:
public partial class tblPreparation : EntityObject, IMyInterface
{
}
It doesn't throw a syntax error but when I run the application I get runtime error: "The type 'tblPreparation' was not mapped. Check that the type has not been explicitly excluded by using the Ignore method or NotMappedAttribute data annotation. Verify that the type was defined as a class, is not primitive or generic, and does not inherit from EntityObject." What am I missing?
I assum it's because they are not in the same namespace. Is there a way to fix this?
I may have misunderstood your comment on the namespace, but for clarity, a Partial class is only actually a partial class when it is in the same namespace of the corresponding partial class, otherwise what you have are just two separate single classes with the same name claiming to be partial. If this is the case, the fix is simple. Put them in same namespace.
However, it is more likely due to adding the EntityObject to the class hierarchy, as oerkelens mentioned. EF 6 creates proxies of your POCOs, for this reason your classes must have parameterless constructors. Adding another class may prevent the db context from creating proxies of your objects.
Remove just that class from the hierarchy, check whether you can materialise these entities to verify or rule it out.
Edit - No, it definitely is due to EntityObject.
I reproduced this by first having my entity implement some interface in a partial class. That worked great. Then I had partial class inherit from EntityObject that failed with your error.
After reproducing this error, I created a class called MyStupidClass and replaced EntityObject with MyStupidClass and I could still materialise entities (even with the top level properties of EntityObject).
So it depends on the class you introduced to the hierarchy.
class Program
{
static void Main(string[] args)
{
using (var db = new schedulerEntities())
{
var schedules = db.Schedules.ToArray();
foreach (var schedule in schedules)
{
Console.WriteLine($"{schedule.Cron} - {schedule.FriendlyDescription}");
}
}
Console.ReadLine();
}
}
public partial class Schedule: MyStupidClass, IScheduler
{
public string FirstName { get; set; }
}
public class MyStupidClass
{
public EntityKey EntityKey { get; set; }
public EntityState State { get; set; }
}
interface IScheduler
{
long Id { get; set; }
string Name { get; set; }
string Cron { get; set; }
}
I have troubles with finding the correct words for this question, so I will try to show you with some code what my problem is.
I have a parent class, which looks like this:
public class ParentClass {
public Guid ParentId { get; }
public int ParentProperty { get; set; }
public List<ParentClass> ParentList { get; set; }
public ParentClass() {
this.ParentId = Guid.NewGuid();
}
}
It is rather simple: It got an ID, a few properties and a List containing elements of itself.
Now I am creating a child class, which looks like this:
public class ChildClass : ParentClass {
public string ChildProperty { get; set; }
public ChildClass() : base() {
this.ParentList = new List<ChildClass>();
}
}
This one got one extra property and a constructor, which contains the problem. I can't initiate a List into the declaration of the List.
I can't just do the declaration of the list in the child class, as I need it in the parent class when I am using it.
What is the best way to solve this problem?
You should use an interface that point both classes (ParentClass as well as ChildClass).
A generic type having a certain type-parameter is a "new" type: So List<ChildClass> and List<ParentClass> are different types.
I think the easiest way to achieve what you want is to initiate the list with its base type : List<ParentClass>
public class ChildClass : ParentClass
{
public string ChildProperty { get; set; }
public ChildClass() : base() {
this.ParentList = new List<ParentClass>();
}
public void AddSomething()
{
// this is ok :
this.ParentList.Add(new ChildClass());
}
}
This could work only if the type List<T> were covariant in T, also known as "out T". However, it is not, and cannot be.
The type List<> allows Add, Insert and others, and so it is not semantically covariant.
In C# (as of currently), class types cannot be made covariant. That is not supported. Only interface and delegate types can be made covariant (or contravariant) in their generic parameters.
The closest we get is IReadOnlyList<out T> which is covariant, so:
IReadOnlyList<ParentClass> parentList = new List<ChildClass>();
is allowed. However, it is not helpful in your case.
public class ParentClass<TChild> where TChild : class
{
public List<TChild> ParentList { get; set; }
public Guid ParentId { get; set; }
public int ParentProperty { get; set; }
public ParentClass()
{
ParentId = Guid.NewGuid();
ParentList = new List<TChild>();
}
}
public class ChildClass : ParentClass<ChildClass>
{
public string ChildProperty { get; set; }
}
I am using ASP.Net Web API 2 and want to create some complex input parameter classes.
I have classes in my library as
public class GrandParent
{
public int Id {get;set;}
public string GrandParentName {get;set;}
}
public class Parent : GrandParent
{
public string ParentName {get;set;}
}
Now I only need Parent class properties in my child class and I am doing so
public class Child : Parent
{
public string ChildName {get;set;}
}
When I create object of Child class, I want only two properties, which are
Child objChild = new Child();
objChild.ParentName;
objChild.ChildName;
I don't want GrandParentName property with objChild. Is there any way to skip grand parent classes in inheritance structure as I want to pass this class as API action parameter.
I am feeling lack of multiple inheritance in C# here.
I may be misunderstanding something but I think you are going too far with inheritance. You might look to the composite pattern.
I think you are confused between the role of each object compared to each others and inheritance. I am not sure you need all these classes. Here is what I would do :
interface IPerson
{
public int Id { get; set; }
public string Name { get; set; }
public string ParentName { get; }
}
class Person : IPerson
{
public int Id { get; set; }
public string Name { get; set; }
protected IPerson Parent { get; set; }
public string ParentName { get { return this.Parent != null ? this.Parent.Name : String.empty; } }
public Person(IPerson parent = null)
{
this.Parent = parent;
}
}
And once you have this, you can achieved what you want :
var grandParent = new Person();
var parent = new Person(grandParent);
var child = new Person(parent);
I hope I didn't miss any crucial point :D.
As it seems, you may need to change your GrandParent from class to interface, then that might work, if you need those properties just make extra class that implements interface. Remember that you can implement as many interfaces as you need on a single class. And still they have common name for use in Lists and stuff.
fharreau gave example.
If you want better example you should make some data diagram concerning data in question.
I have the following classes:
public class ParentClass
{
public string Name {get;set;}
public int Age {get;set;}
}
public class SubClass : ParentClass
{
public int Id {get;set;}
}
and I have the following method:
public void InsertSubClass(ParentClass parentClass)
{
SubClass subClass = new SubClass();
subClass.Id = 1;
subClass.Age = parentClass.Age;
subClass.Name= parentClass.Name;
}
How can I refactor this method in such a way that I dont need to assign the properties of the parameter ParentClass into properties of SubClass one by one?
Are there any alternative which is more efficient? or this is really how to do it? Im just thinking that if the properties are many, this could be tedious..
Thanks in advance. :)
you can achieve this thing by creating copy constructor. Anyways you would have to assign parent class properties somewhere as casting wont work in this case.
Here is copy constructor way that assigns parent property in parent constructor.
public class ParentClass
{
public string Name { get; set; }
public int Age { get; set; }
public ParentClass()
{
}
//Copy constructor
public ParentClass(ParentClass parentClass)
{
this.Name = parentClass.Name;
this.Age = parentClass.Age;
}
}
public class SubClass : ParentClass
{
public int Id { get; set; }
public SubClass(ParentClass parentClass, int id) : base(parentClass)
{
this.Id = id;
}
}
And now method looks like this.
public static void InsertSubClass(ParentClass parentClass)
{
SubClass subClass = new SubClass(parentClass, 1);
}
Update
If you can not make changes to your parent and child class then how about creating an extension method for the parent class in static class like below.
public static void ShallowConvert<T, U>(this T parent, U child)
{
foreach (PropertyInfo property in parent.GetType().GetProperties())
{
if (property.CanWrite)
{
property.SetValue(child, property.GetValue(parent, null), null);
}
}
}
Note: This might not work with private properties and fields.
You can not assign parent class to child's base object like this child.base = parent. Also you can not cast paret class to child like var o = (child)parent; o.id=1; All you can do is add constructor to child class that receives parent class and do work in that constructor.
I'm wondering if someone can help me with what is the best way to populate the base properties of a derived class. I would like to use one method to populate the properties of the base whether the base or the child is being used.
Here is an example of what I am asking:
public class Parent
{
public string Id {get; set;}
}
public class Child : Parent
{
public string Name {get; set;}
}
public Parent GetParent(int ID)
{
Parent myParent = new Parent();
//Lookup and populate
return Parent;
}
public Child GetChild(string name)
{
Child myChild = new Child();
//Use the GetParent method to populate base items
//and then
//Lookup and populate Child properties
return myChild;
}
I think you might be overcomplicating things a bit. Take a look at this code that uses inheritance and constructors to initialize objects:
public class Parent
{
public string Id {get; set;}
public Parent(string id)
{
Id = id;
}
}
public class Child : Parent
{
public string Name {get; set;}
public Child(string id, string name) : base(id) // <-- call base constructor
{
Name = name;
}
}
It uses constructors for initialization and the base keyword to call the parent constructor from the derived class. I would go this direction unless you really need to have a factory method construct your object.
Something like this if you don't want to do it in constructor.
Note: the constructor is not always called, especially if the type is desirialized using certain serializators.
public class Parent
{
public string Id {get; set;}
public virtual void InitPorperties() {
//init properties of base
}
}
public class Child : Base {
public override void InitProperties() {
//init Child properties
base.InitProperties();
}
}
After this you can use it like:
public Parent GetParent(int ID)
{
var myParent = new Parent();
parent.InitProperties();
return myParent;
}
public Parent GetChild(int ID)
{
var child= new Child();
child.InitProperties();
return child;
}
As anything it has other side of coin: the caller has to call InitProperties method in oder to get correctly initialized object.
If the serialization/desialization is not a concern in your case, stick with constructors, in practice call this methods inside ctors of every type (Parent, Child)
If you dont want to use a standard way to just
Child myChild = new Child();
myChild.Name = "name";
myChild.Id = "1";
You can populate them via the constructor like this.
public class Parent
{
public Parent(string id)
{
Id = id;
}
public string Id { get; set; }
}
public class Child : Parent
{
public Child(string id, string name)
: base(id)
{
name = Name;
}
public string Name { get; set; }
}
And when you isntanciate it
Child myChild = new Child("1", "name");
Which in my opinion is a quite neat way to do it.