Consider the following scenario:
public abstract class Entity
{
public object Id { get; set; }
}
public abstract class Entity<T> : Entity
{
public new T Id { get; set; }
}
public class Foo : Entity<Guid>
{
}
If I have the following code:
var foo = new Foo { Id = Guid.NewGuid() };
db.Foos.Add(foo);
db.SaveChanges();
I'm getting a DbEntityValidation exception saying that Id is not allowed to be null. If I debug, I can see that Foo.Id does indeed have a value, but if I go into the base object down to the level of Entity, Id is null there, and it seems that is what Entity Framework is using to validate against rather than the non-shadowed property. I feel like I'm missing something really basic here; maybe I just haven't had enough coffee yet this morning. Any ideas what might be the problem?
The problem is that
public new T Id { get; set; }
...in Entity<T> hides the Id property in Entity. If you do this:
var foo = new Foo { Id = Guid.NewGuid() };
Entity entity = foo as Entity;
Console.WriteLine(entity.Id);
...that's not going to return a Guid, it's going to return what's behind Entity.Id which is an object which has not been set.
Edit:
Chris came up with this, which should work fine.
public abstract class Entity<T> : Entity
{
public new T Id
{
get { return (T)base.Id; }
set { base.Id = value; }
}
}
Yes, I missed something simple: Entity Framework is incompetent and doesn't support property shadowing. I thought it did because in the past I've successfully used shadowing to alter property attributes (e.g. make the property only required in a subclass), but I've never gone so far as to actually attempt to change the type.
UPDATE
It occurred to me that if I just set the base property with the right value, everything would be fine. So, I changed my Entity<T> class to the following:
public abstract class Entity<T> : Entity
{
public new T Id
{
get { return (T)base.Id; }
set { base.Id = value; }
}
}
The exception went away and the object was saved to the database successfully. Are there any unforeseen consequences to doing this that I'm missing?
Related
I have a base class A and derived class B. B is introduced in my latest migration. I am going for a Table-per-Type inheritance. There can be many Bs for one A. The error I am getting when trying to update-database is related the Index on A.Designation, because the DB gets populated by the Seed method. I do understand where this error comes from, but I do not know how to avoid it.
The base class:
[Table("As")]
class A
{
[Key]
public Id { get; set; }
[Index(IsUnique = true)]
public string Designation { get; set; }
// This is mapped via EF and required by Bs constructor
public ICollection<SomeType> SomeType { get; set; }
// Parameter less constructor for EntityFramework
private A() { }
public A(string designation)
{
Designation = designation;
}
}
The derived class:
[Table("Bs")]
class B : A
{
public B(A a) : base(a.designation)
{
foreach (SomeType someType in A.SomeTypes)
{
// Do something
}
}
}
So in the Seed method first an instance a of A, then an instance b of B based on a is added to the DB.
As I understand it, calling new B(a) creates a new instance of A which also is added to the DB which fails because of the unique index.
How do I avoid this?
I want the data to be referenced, not duplicated. I guess it would be possible to use a Table-per-Hierarchy scheme but that would duplicate the data of A for each B, (right?) which I would like to avoid, especially because A.SomeEntities would have its entries duplicated as well.
Another possibility that just popped into my mind, is passing the the Id of a to b's constructor, but that would then have to call the DbContext and probably imply some other weirdness I am missing right now.
Looks like you are trying to link with existing object instead of class inheritance?
Why not create a link between your b and a?
[Table("Bs")]
class B
{
public A referredA {get;set;}
public B(A a)
{
referredA=a;
}
}
I have a bunch of classes that formulate various variations of items. I currently have a class like this:
public class Item {
public ItemFile file { get; set;}
public ItemCalendar calendar { get; set;}
public ItemWebsite website { get; set;}
}
ItemFile etc are classes made using Entity Framework and map to the database tables that provide the information relating to that type of item. The item class only has one of the internal properties actually instantiated.
I can see the number of items growing to around 25 or more. I don't feel right making the view model containing 25 properties where 24 of them are null with only one being not null.
I want something that can work with entity framework and return a class that can return only it's actual type. Therefore if I ask for the variation of the item I would get back ItemFile for files and ItemCalendar for calendars.
I've tried something like this:
public class Item
{
public ItemBase item { get; set; }
}
public class ItemBase
{
public Type typeName { get; set; }
public object ItemInstance { get; set; }
public typeName GetInstance()
{
return Convert.ChangeType(ItemInstance, typeName);
}
}
But then I don't know how to return ItemFile as public typeName is an error.
I then tried:
public class Item
{
public ItemBase<ItemFile> item { get; set; }
}
public class ItemBase<T>
{
public T ItemInstance { get; set; }
}
But to get that to work, I had to hardcore FileItem in the <> on the item class which goes back into knowing the type before hand.
Is there anyway to get this to work? Bonus points if it can work with entity framework as I'm pulling back the classes from there. Worst comes to worst if it doesn't work entity framework wise is I can pull it all and then convert it into the form that answers the question.
If the title of the question is wrong, feel free to edit. I wasn't sure how to ask.
tl;dr version: I want to be able to return multiple types of classes from a function using a type that is passed in not using <>.
Edit 1:
I forgot to show my inheritence example. I've tried this but also got stuck with something similar to the above.
public class ItemBase
{
public Type typeName { get; set; }
public object ItemInstance { get; set; }
public typeName GetInstance()
{
return Convert.ChangeType(ItemInstance, typeName);
}
}
public class ItemFile : ItemBase
{
public String FileName { get; set; }
}
public class Test
{
public void testFunction()
{
//Made this just so the compiler didn't complain.
ItemFile testFile = new ItemFile();
//I can use a function to get the item base.
ItemBase baseItem = testFile;
//How do I do this? Use a function to get the ItemFile from the instance.
ItemFile finalItem = baseItem.GetInstance();
}
}
I want to be able to return multiple types of classes from a function using a type that is passed in not using <>.
<> (generics) are the mechanism by which a function can explicitly return more than one type. Without generics the function returns whatever type it says it returns.
object SomeFunction() // Returns an object
ItemBase SomeOtherFunction () // returns ItemBase
In the above examples, SomeFunction can still return any type (because all types inherit from object.) But it won't be explicit. All you know for sure is that it's an object.
Similarly, SomeOtherFunction can return an ItemBase or any class that inherits from ItemBase. But that's all you know about it.
Ideally you don't want to have functions returning one type (like object or ItemBase) and then cast the result of the function to another more specific type. The function should return what you want, and you should want what the function returns. Generics help with that. For example:
public TItem Instance<TItem>() where TItem : ItemBase
allows a function to return a specified type as long as it is an ItemBase or inherits from one.
This last comment is going to seem odd or useless but it's the truth. If you find yourself in a scenario where the above rules don't work and you need to be able to do something that you can't do or shouldn't do, go back and rethink why you're trying to do that. That's where the real problem is.
That means you probably need to go back a step and get yourself out of the situation where you're trying to work against the language. What are you trying to accomplish and how can you do it in a way that works with the language, not against it?
I believe this is about as close as you're going to get.
using System;
using System.Reflection;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
EFTypeData itemData = GetItemData();
var asmName = Assembly.GetExecutingAssembly().GetName().Name;
var type = Type.GetType($"ConsoleApplication1.{itemData.TypeName}, {asmName}");
var instance = Activator.CreateInstance(type);
var item = new Item<Object>()
{
ItemBase = instance
};
}
private static EFTypeData GetItemData()
{
return new EFTypeData() { TypeName = "ItemFile" };
}
}
class EFTypeData
{
public string TypeName { get; set; }
}
class Item<T> where T: class
{
public T ItemBase { get; set; }
}
class ItemFile
{
public string FileName { get; set; }
}
}
This will, given a string "ItemFile", create an instance and assign it to Item. If you run this and inspect item, you have
The big caveat to this is that at compile-time, all you have is an Object as your ItemBase. And without hard-coding your Type (i.e. var item = new Item<ItemFile>();), you're never going to know more.
That said, with this method you are perfectly clear to iterate over fields and such using Reflection. But this is a limitation of this level of run-time object manipulation.
I'm using Entity Framework with Code first. My Relationship properties keep breaking.
I have the object Element:
public class Element : IElement
{
// ... some event handlers (removed)
[Key]
public Guid ID { get; set; } = Guid.NewGuid();
public string Name { get; set; }
// navigation properties
public virtual ElementType ElementType { get; private set; }
public virtual NotifiableCollection<Property> Properties { get; private set; } = new NotifiableCollection<Property>();
// Parameterless constructor for serialization
private Element() { }
public Element(ElementType elementType) : base()
{
// loop through and create Properties for each Property Type
ElementType = elementType;
if (ElementType?.PropertyTypes != null)
{
ElementType.PropertyTypes.ToList().ForEach((property) =>
{
Properties.Add(new Property(property));
});
}
}
}
And ElementType:
public class ElementType : IElementType
{
// ... some event handlers (removed)
[Key]
public Guid ID { get; set; } = Guid.NewGuid();
public string Name { get; set; }
// navigation properties
public virtual NotifiableCollection<PropertyType> PropertyTypes { get; set; } = new NotifiableCollection<PropertyType>();
public virtual NotifiableCollection<Element> Elements { get; set; } = new NotifiableCollection<Element>();
public ElementType()
{
// ensure our Element's get updates
PropertyTypes.CollectionChanged += (e, a) =>
{
//update the database to send out renewal to interested entities
if (a.ChangeType == ChangeType.Added)
{
foreach (Element element in Elements)
{
element.Properties.Add(new Property(a.Item));
}
}
};
}
}
It works fine when I create these objects the first time (as I've explicitly set the navigation properties then saved):
However, when I then close everything and get these from the database:
The navigation properties are not resolved. The table definitions set up the foregn key relationship fine:
CREATE TABLE [dbo].[Elements] (
[ID] UNIQUEIDENTIFIER NOT NULL,
[Name] NVARCHAR (MAX) NULL,
[ElementType_ID] UNIQUEIDENTIFIER NULL,
CONSTRAINT [PK_dbo.Elements] PRIMARY KEY CLUSTERED ([ID] ASC),
CONSTRAINT [FK_dbo.Elements_dbo.ElementTypes_ElementType_ID] FOREIGN KEY ([ElementType_ID]) REFERENCES [dbo].[ElementTypes] ([ID])
);
GO
CREATE NONCLUSTERED INDEX [IX_ElementType_ID]
ON [dbo].[Elements]([ElementType_ID] ASC);
and I can see the data is all correct:
ID Name ElementType_ID
ff186746-62cb-4246-9c64-f2d007b23ac0 Aircon Test 27/03/2017 12:54:03 57d93ac1-ad3b-4718-a593-80639cc24907
which matches an ID in ElementType table.
I have this set in my repository:
context.Configuration.ProxyCreationEnabled = true;
context.Configuration.LazyLoadingEnabled = true;
And the context is still active at the time where I'm trying to resolve this property.
Everything was working, but I've had this problem multiple times with EF, where my navigation properties just break randomly. I don't remember touching any of the code associated with this element, just ran it and now it doesn't work. Can anyone help?
Edit: This is the repository code:
public sealed class Repository : IRepository
{
public event ObjectMaterializedEventHandler ObjectMaterialized;
public Repository() {
(context as IObjectContextAdapter).ObjectContext.ObjectMaterialized += ObjectContext_ObjectMaterialized; ;
context.Configuration.ProxyCreationEnabled = true;
context.Configuration.LazyLoadingEnabled = true;
}
// I do this to wire in some events later
private void ObjectContext_ObjectMaterialized(object sender, ObjectMaterializedEventArgs e)
{
ObjectMaterialized?.Invoke(this, e);
}
private DataContext context = new DataContext(false);
public IEnumerable<T> GetAll<T>() where T : class
{
return context.Set<T>().ToList() as IEnumerable<T>;
}
public T GetItem<T>(Guid id) where T : class
{
return context.Set<T>().Find(id) as T;
}
...
}
the context stores them like this:
public class DataContext : DbContext
{
...
public DbSet<Element> Elements { get; set; }
public DbSet<ElementType> ElementTypes { get; set; }
}
I think it IS something to do with accessing. I'm accessing the Element with context.Set().Find(id) as T, and it fails. However, if I navagate through the ElementTypes, find it's list of Entities, then it works fine.
Found the answer with the help of Ivan in the comments.
The issue is with having a private constructor:
// Parameterless constructor for serialization
private Element() { }
One of the requirement for proxies is a public or protected constructor:
For either of these proxies to be created: A custom data class must be
declared with public access.
A custom data class must not be sealed (NotInheritable in Visual
Basic)
A custom data class must not be abstract (MustInherit in Visual
Basic).
A custom data class must have a public or protected constructor that
does not have parameters. Use a protected constructor without
parameters if you want the CreateObject method to be used to create a
proxy for the POCO entity. Calling the CreateObject method does not
guarantee the creation of the proxy: the POCO class must follow the
other requirements that are described in this topic.
The class cannot implement the IEntityWithChangeTracker or
IEntityWithRelationships interfaces because the proxy classes
implement these interfaces.
The ProxyCreationEnabled option must be set to true.
For lazy loading proxies: Each navigation property must be declared as
public, virtual (Overridable in Visual Basic), and not sealed
(NotOverridable in Visual Basic) get accessor.
I'm not sure the title reflect the question that I was meant, but..
Let's say I have two classes, Entity and Component:
public abstract class Entity
{
private List<Component> _components = new List<Component>();
public void AddComponent<T>()
where T : Component
{
T component = (T)Activator.CreateInstance(typeof(T));
component.Owner = this;
_components.Add(component);
}
}
public abstract class Component
{
public Entity Owner { get; protected set; }
public abstract void Update();
}
As you may notice, above classes are abstract classes which mean is not intended for direct use. However, on the later stage of development, I'm aware that some Component require ability that only attachable / Added by specific class that inherited to Entity class.
So, I added a class Component<T> that inherit Component:
public abstract class Entity
{
private List<Component> _components = new List<Component>();
public void AddComponent<T>()
where T : Component
{
T component = (T)Activator.CreateInstance(typeof(T));
component.Owner = this;
_components.Add(component);
}
}
public abstract class Component
{
public Entity Owner { get; protected set; }
public abstract void Update();
}
public abstract class Component<T> : Component
{
// I hide the base.Owner with new keyword
// feel free to suggest me in case there is better approach to do this
new public T Owner
{
get { return (T)base.Owner; }
protected set { base.Owner = value; }
}
}
And now, let's say I have Foo, Bar and Processor class:
public class Foo : Entity
{
public int FooValue { get; set; }
}
public class Bar : Entity
{
public int BarValue { get; set; }
}
public class Processor : Component<Foo>
{
public override void Update()
{
Owner.FooValue = 10;
}
}
What I want to do is to make Processor class only add-able by Foo object. Currently AddComponent ignore it, so I don't know how to do that:
var foo = new Foo();
var bar = new Bar();
foo.AddComponent<Processor>(); // OK
bar.AddComponent<Processor>(); // Compiler should give an error at this point
I also tried to do this:
public void AddComponent<T, X>()
where T : Component<X>
where X : Entity
{
T component = (T)Activator.CreateInstance(typeof(T));
component.Owner = this;
_components.Add(component);
}
However, it require me to explicitly specify the X constraint:
foo.AddComponent<Processor, Foo>();
bar.AddComponent<Processor, Bar>(); // Error, but the syntax is weird!
Any ideas?
Your post isn't clear on what constraints, if any, you have on your basic Entity and Component classes. So I don't know if the below will be feasible in your scenario. That said, I believe that if it's not, you won't be able to do what you want because otherwise the generic type parameters won't be known by the compiler.
The solution, absent any other constraints, is to make your Entity class generic, and provide the sub-class type itself as the type parameter:
class Entity { }
class Entity<T> : Entity where T : Entity<T>
{
public void AddComponent<U>(U value) where U : Component<T> { }
}
class Component<T> where T : Entity { }
class Foo : Entity<Foo> { }
class Bar : Entity<Bar> { }
class P : Component<Foo> { }
I know it looks weird. But you're basically asking for a self-referential graph of generic type dependencies, and in C# code the above is what that looks like.
You can call the AddComponent() method using type inference (so no generic parameter needed). If you try to call it with the wrong type of Component<T> object, you'll get a compiler error:
Foo foo = new Foo();
Bar bar = new Bar();
P p = new P();
foo.AddComponent(p);
bar.AddComponent(p); // CS0311
Note: I would strongly recommend against hiding class members. It doesn't really affect your question as stated (i.e. you could have left that detail out completely), but having two different properties with the same name is just asking for bugs. If you must use hiding, IMHO you should at least have the new property use the hidden property. E.g.:
class Component
{
public Entity Owner { get; protected set; }
}
class Component<T> : Component where T : Entity
{
new public T Owner
{
get { return (T)base.Owner; }
set { base.Owner = value; }
}
}
You won't get compile-time checking on assignments to the non-generic Component.Owner property, but at least you'll get a run-time error if some code tries to dereference the Owner property as the generic version, if and when the wrong type was assigned by the base type for some reason.
For example I have following domain model:
class Order {
public virtual int Id {get; protected set;}
public virtual BaseStatus Status {get; set;}
}
abstract class BaseStatus {
public virtual int Id {get; protected set;}
public abstract string Name {get;}
}
class Approved : BaseStatus {
public override string Name
{
get { return "Approved"; }
}
}
So now what I wan't to have is two tables, Orders and Statuses. Where Orders table will have StatusId column.
The question is about API of changing order status. If I do the following:
order.Status = new Approved();
That will lead to creation of new row in statuses table.
Currently I have created following helper:
class StatusesFactory {
ISession session;
public StatusesFactory(ISession session){
this.session = session;
}
public GetStatus<T> where T : BaseStatus, new() {
T status = session.QueryOver<T>.SingleOrDefault();
if(status == null){
status = new T();
session.SaveOrUpdate(status);
}
return status;
}
}
And when I want to set status I'm using such code:
order.Status = statusesFactory.GetStatus<Approved>();
It seems to work fine, but to be complex with no reason. I'm using NHibernate but I think the same question may be applied to any ORM. The reason for such a thing is easy deployment on empty data base so that it is filled on first requests.
How do you handle dictionary tables?
Does my approach have obvious down sides that I can't see?
One problem that I see here is when I need to get all possible statuses I cant use code like:
session.QueryOver().List();
because not all statuses may be created yet.
So what do you think?
good question ...
i'd think that your Approved-class should use make use of the singleton pattern, since there can be only one Approved-state ...
the list of all existing vs. all possible states is a bit more difficult ... the possible states depend on what classes inherit from BaseState... i have no idea how to find those fast, since they don't have to reside in the current assembly, or even in a loaded assembly ... you should think about a static list of all subclasses singleton objects in BaseStatus ...