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.
Related
I am creating 2 poco types during runtime (using reflection). These two should reference each other. Later instances of these pocos can be stored in the database using entity framework.
Currently I am faced by two problems:
It's not possible or at least I don't know how I am able to code this two-way referencing (because while whone Poco is described, the type of the other poco doesen't exist).
2.As I've found no answer to problem 1, I've decided to use object as the type of the references. So the Models now contain the following line:
$ public object Poco1 {get; set;}
And:
public object Poco2 {get; set;}
The usage of object confronts me now with another problem. Because, during the OnModelCreating an exception is thrown, that object needs to contain an id.
As much as I understand, this means, that ef core thinks, that "object" would be the type of the model, that should be referenced.
Does anybody have an idea on how I can do what I want?
Thanks :)
Whenever I hit a problem involving generics and reflection. I find it easier to start by solving the generic part of the problem, in a generic method;
public class Parent<TChild> where TChild : class
{
public ICollection<TChild> Children { get; set; }
}
public class Child<TParent> where TParent : class
{
public TParent Parent { get; set; }
}
public void DefineRelationship<TParent, TChild>(ModelBuilder modelBuilder)
where TChild : Child<TParent>
where TParent : Parent<TChild>
{
modelBuilder.Entity<TParent>()
.HasMany(p => p.Children)
.WithOne(c => c.Parent);
}
Now you need to use reflection to invoke the method with the correct types.
Your entities should look something like this:
public class Poco1
{
public int Id {get; private set;}
...
public Poco2 Poco2 {get; private set;}
public void SetPoco2(Poco2 poco2)
{
Poco2 = poco2;
}
}
public class Poco2
{
public int Id {get; private set;}
...
public int Poco1Id {get; private set;}
public Poco1 Poco1 {get; private set;}
}
And then setting them up:
async Task SomeMethod()
{
var poco1 = new Poco1();
var poco2 = new Poco2();
poco1.SetPoco2(poco2);
//at first only poco1 has reference to poco2
//and poco2 does not have reference to poco1 yet
Debug.Assert(poco1.Poco2 == poco2);
Debug.Assert(poco2.Poco1 != poco1);
await _someRepository.AddAsync(poco1);
await _someRepository.SaveChnagesAsync();
//After saving changes EF core manages the primary keys and references
Debug.Assert(poco1.Poco2 == poco2);
Debug.Assert(poco2.Poco1 == poco1);
}
and modelBuilder:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
var poco1Builder = modelBuilder.Entity<Poco1>();
poco1Builder.HasKey(x => x.Id);
poco1Builder
.HasOne(x => x.Poco2)
.WithOne(x => x.Poco1)
//Poco2 will have Poco1Id in db that will be used for reference
//Also Poco1Id does not have to be set manually, EF core takes care of that
.HasForeignKey<Poco2>(x => x.Poco1Id);
;
var poco12Builder = modelBuilder.Entity<Poco2>();
}
Also if reference is needed before saving to db SetPoco2 can be modified as:
public void SetPoco2(Poco2 poco2)
{
Poco2 = poco2;
poco2.SetPoco1(this);
}
and set method in Poco2:
public void SetPoco1(Poco1 poco1)
{
Poco1 = poco1;
}
Too way references are dangerous for big projects for poor maintainability
i would like to implement a dynamic way of creating entities for EntityFramework Core. Therefore i created a base class which adds some basic functionallity to entities. My goal is to achieve a entity handling which can be done with the entity classes exclusively.
This Example should create a User and set the fields Then it should automatically save the changes:
new User()
{
Email = "test123#abc.com",
PwdHash = "some-hash"
}
I already created a base class for that to handle such actions in background:
public abstract class Entity<T> where T : Entity<T>
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public static T Find(params object[] keyValues)
{
var dc = EntityManager.GetContext();
return dc.Find<T>(keyValues);
}
public static List<T> Find(Expression<Func<T, bool>> _condition)
{
var dc = EntityManager.GetContext();
return dc.Set<T>().Where(_condition).ToList();
}
public void Delete()
{
var dc = EntityManager.GetContext();
dc.Set<T>().Remove((T)this);
dc.SaveChanges();
}
public void Commit()
{
var dc = EntityManager.GetContext();
dc.SaveChanges();
}
}
EntityManager simply maintains a DbContext which is working quite fine.
the Entity class is working quite fine too, but i need a way of getting notified on when a property of the subclass (T) is beeing changed to invoke the "Commit()" method.
Currently i am using the property setter:
public class User : Entity<User>
{
[Required]
public string Email {
get => _email;
set { _email = value; Commit(); }
}
private string _email = "";
[Required]
public string PwdHash {
get => _pwdHash;
set { _pwdHash = value; Commit(); }
}
private string _pwdHash = "";
}
But that is not what i want. I would like to simply create a automated property which gets that Commit method appended by the base class automatically. Is that in anyway possible?
I am not sure in terms of exact technical specification for this problem to me but in simple words I am trying to create a wrapper/extension method around to save my entities.
So I added new Entity Data Model (.edmx) file to my project. That generates DbSet(s) like this-
public partial class SUContextContainer : DbContext
{
public SUContextContainer()
: base("name=SUContextContainer")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public DbSet<Category> Categories { get; set; }
public DbSet<Gallery> Galleries { get; set; }
public DbSet<SuperUser> SuperUsers { get; set; }
public DbSet<UserType> UserTypes { get; set; }
}
Now here I am trying to wrap this into an extension method for database operations like (save, delete, update etc..)
I tried creating it as -
public static void Save(this EntityObject objEntity)
{
try // Update Record
{
((IObjectContextAdapter)Global.Context).ObjectContext.ObjectStateManager.ChangeObjectState(objEntity, EntityState.Modified);
Global.Context.SaveChanges();
}
catch (OptimisticConcurrencyException) // Insert Record
{
((IObjectContextAdapter)Global.Context).ObjectContext.ObjectStateManager.ChangeObjectState(objEntity, EntityState.Added);
Global.Context.SaveChanges();
}
}
This method is attached to EntityObject types. Where .edmx code which it generates are of type DbContext.
So Whenever I try to save some entity with this helper method it never finds out.
var galleryEntity = new Gallery {
IsActive = true,
CategoryId = model.CategoryId,
};
galleryEntity.Save(); // the save method is not found.
I tried above method to change in -
public static void Save(this DbSet objEntity)
But this also doesn't seem to take as extension method.
What am I doing wrong.
So Whenever I try to save some entity with this helper method it never
finds out.
It will not, because gallery is just a class and is not inherited from EntityObject.
I don't suggest adding inheritence or modifiying autogenerated classes.
Use power of partial classes:
You can create patial classess for your models with interface.
public partial class Gallery : IEntity
{
//This is your class different than auto generated class by Ef.
}
Also you shouldn't use try catch for decision. That's why you should seperate update and create and make decision on upper level (without try catch).
So your extension methods should be like this.
public static int Update<T>(this T entity) where T : IEntity
{
using(var dbContext=new SUContextContainer())
{
var entry = dbContext.Entry(entity);
dbContext.Set<T>().Attach(entity);
entry.State = EntityState.Modified;
return dbContext.SaveChanges();
}
}
public static int Create<T>(this T entity) where T : IEntity
{
using(var dbContext=new SUContextContainer())
{
dbContext.Set<T>().Add(entity);
return dbContext.SaveChanges();
}
}
Your extension method will only apply to types that inherit from EntityObject.
You will either need to make all of your entity classes inherit from this EntityObject class or create another extension method that applies to the correct type.
Typically when using these kind of persistence patterns you would create an entity base class
public class Entity
{
public int Id { get; set; }
}
and each entity type inherits from it
public class Gallery : Entity
{
public int Name { get; set; }
}
Then you can have common methods that you use across entity types:
public static void Save(this Entity entity);
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.
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?