AutoMapper Map entity with self-reference entity - entity-framework

I have a small problem that gives me a StackOweflow problem.
I use EF 4.1 with complextypes and this works, the problem is that you need to create an instance of the complextype even if all the values are null, to make it work with EF.
So now I have a class that looks like this..
public class GoodsItem{
public GoodsItem InnerGoodsItem{get;set;}
//-- A lot of other properties needed for this class
public GoodsItem()
{
this.InnerGoodsItem = new GoodsItem();
}
}
I need the code in the constructor for EF to work as it should, but then every time I create a GoodsItem it creates a new GoodItems that creates a new GoodsItem and so on...
How can I solve this problem with AutoMapper and still keep EF 4.1 happy.
Thanks in advanced...

Can't see how that constructor could ever work. Perhaps you could change your class to initialize the inner item in the property get, like this:
public class GoodsItem{
private GoodsItem _innerGoodsItem;
public GoodsItem InnerGoodsItem
{
get
{
if (_innerGoodsItem == null) _innerGoodsItem = new GoodsItem();
return _innerGoodsItem;
}
set { _innerGoodsItem = value; }
}
//-- A lot of other properties needed for this class
public GoodsItem()
{
//No longer need this call in ctor
//this.InnerGoodsItem = new GoodsItem();
}
}
Not sure if this will cause a problem with EF though (thankfully, I've pretty much avoided EF so far!).

Related

Summary column on EF

Is it possible to add summary properties(no database column) according LINQ from another property(column) in EF generated class from database and this property don't update(delete or remove from class) when update model from database(because this property(cloumn) is not on database)
Yes, it is. Classed generated by Entity Framework as an Entitied are always marked partial. It lets you extend the functionality with your own properties or method.
Let say your entity class is named Post. You can extend it with code like that:
public partial class Post
{
public int Average
{
get
{
return this.Items.Average();
}
}
}
Because it's not a part of designer-generated file it won't be overwritten when it's regenerated. However, there is one requirement to make it work: your custom part of Post class has to be in exactly the same namespace as code generated by EF.
Try using the [NotMapped] attribute on a property in a partial class. This will be ignored by Entity Framework.
public partial class EntityName
{
[NotMapped]
public int CalculatedProperty
{
get
{
return Numbers.Sum();
}
}
}

How can I prevent EF from inserting an object that already exists in the db when adding one that contains this first one?

It's quite self-explainatory.
I have a class that contains another
Let's call them Subject and Classroom
public class Subject
{
public Classroom Class {get; set;}
}
I'm using stateless facades, wich means my DbContext is disposed right after recovering the objects and is created to store the new ones.
Shouldn't it know that Classroom isn't a new object since it's ID is already in the DB?
Using the debugger I can track to the point right before I call the SaveChanges method and Classroom.id is the one I have on the database.
What's the problem? EF adds a new Classroom with the exact properties as the previous one, but with a new PK.
What am I doing wrong here?
This is the code used for the general CRUD operations (They are in my DbContext) Both update and delete work just fine:
public void Update(DbSet MySet, object Obj)
{
MySet.Attach(Obj);
var Entry = this.Entry(Obj);
Entry.State = EntityState.Modified;
this.SaveChanges();
}
public void Insert(DbSet MySet, object Obj)
{
MySet.Add(Obj);
this.SaveChanges();
}
public void Delete(DbSet MySet, object Obj)
{
MySet.Attach(Obj);
var Entry = this.Entry(Obj);
Entry.State = EntityState.Deleted;
this.SaveChanges();
}
Without seeing you're actual code on how you're either updating or creating your Subject entity, it's hard to tell. However, you're probably not attaching the Classroom so EF is assuming that the entity is new, when it's really not.
using (Model m = new Model())
{
m.Subject.Add(subject);
m.Classrooms.Attach(subject.Class);
m.SaveChanges();
}
Even though the PK is the same, without attaching to the Context, EF has no way of figuring out what you're intention is. Attaching the entity explicitly tells your context what you want.

Why is my Entity Framework Code First proxy collection null and why can't I set it?

I am using DBContext and have two classes whose properties are all virtual. I can see in the debugger that I am getting a proxy object when I query the context. However, a collection property is still null when I try to add to it. I thought that the proxy would ensure that collection is initialized.
Because my Poco object can be used outside of its data context, I added a check for the collection being null in the constructor and create it if necessary:
public class DanceStyle
{
public DanceStyle()
{
if (DanceEvents == null)
{
DanceEvents = new Collection<DanceEvent>();
}
}
...
public virtual ICollection<DanceEvent> DanceEvents { get; set; }
}
That works outside the data context but if I retrieve an object using a query, although the test is true, when I try to set it, I get following exception: 'The property 'DanceEvents' on type 'DanceStyle_B6089AE40D178593955F1328A70EAA3D8F0F01DDE9F9FBD615F60A34F9178B94' cannot be set because the collection is already set to an EntityCollection.'
I can see it is null and I cannot add to it, but neither can I set it to a collection because the proxy says it is already set. Therefore I cannot use it. I'm confused.
Here is the DanceEvent class:
public class DanceEvent
{
public DanceEvent()
{
if (DanceStyles == null)
{
DanceStyles = new Collection<DanceStyle>();
}
}
...
public virtual ICollection<DanceStyle> DanceStyles { get; set; }
}
I have omitted the other value-type properties from the code above. I have no other mappings for those classes in the context class.
As you correctly observed in the answer to your own question, removing the "virtual" keyword from the collection properties works around the problem, by preventing the Entity Framework from creating a change tracking proxy. However, this is not a solution for many people, because change tracking proxies can be really convenient and can help prevent issues when you forget to detect changes at the right places in your code.
A better approach would be to modify your POCO classes, so that they instantiate the collection properties in their get accessor, rather than in the constructor. Here's your POCO class, modified to allow change tracking proxy creation:
public class DanceEvent
{
private ICollection<DanceStyle> _danceStyles;
public virtual ICollection<DanceStyle> DanceStyles
{
get { return _danceStyles ?? (_danceStyles = new Collection<DanceStyle>()); }
protected set { _danceStyles = value; }
}
}
In the above code the collection property is no longer automatic, but rather has a backing field. It's better if you leave the setter protected, preventing any code (other than the proxy) from subsequently modifying these properties. You will notice that the constructor was no longer necessary and was removed.
I found the solution to this problem here: Code First adding to collections? How to use Code First with repositories?
I removed 'virtual' from all properties except collections and lazy loaded objects, that is, all native types.
But I still don't understand how you can end up with the situation where you have a null collection that you cannot use and have no way to set it to a valid collection.
I also found this answer from Rowan Miller on an MSDN forum
Hi,
If you make all your properties virtual then EF will generate proxy classes at runtime that derives from your POCO classed, these proxies allow EF to find out about changes in real time rather than having to capture the original values of your object and then scan for changes when you save (this is obviously has performance and memory usage benefits but the difference will be negligible unless you have a large number of entities loaded into memory). These are known as 'change tracking proxies', if you make your navigation properties virtual then a proxy is still generated but it is much simpler and just includes some logic to perform lazy loading when you access a navigation property.
Because your original code was generating change tracking proxies, EF was replacing your collection property with a special collection type to help it find out about changes. Because you try and set the collection back to a simple list in the constructor you are getting the exception.
Unless you are seeing performance issues I would follow Terrence's suggestion and just remove 'virtual' from your non-navigation properties.
~Rowan
So it appears that I only have the problem with a full 'change tracking proxy' if all my properties are virtual. But given that, why can I still not use the virtual property on the change tracking proxy? This code blows up on line three because ds2.DanceEvents is null and cannot be set in the constructor:
DanceStyle ds2 = ctx.DanceStyles.Where(ds => ds.DanceStyleId == 1).Single();
DanceEvent evt = CreateDanceEvent();
ds2.DanceEvents.Add(evt);
I'm still confused, even though my code is now working because of the fix above.
Old question...
Poco class:
public partial class MyPOCO
{
public MyPOCO()
{
this.MyPocoSub = new HashSet<MyPocoSub>();
}
//VIRTUAL
public virtual ICollection<MyPocoSub> MyPocoSub { get; set; }
}
and proxy code:
public override ICollection<MyPocoSubSet> MyPocoSubSets
{
get
{
ICollection<MyPocoSubSet> myPocoSubSets = base.MyPocoSubSets;
if (!this.ef_proxy_interceptorForMyPocoSubSets(this, myPocoSubSets))
{
return base.MyPocoSubSets;
}
return myPocoSubSets;
}
set
{
if (value != this.RelationshipManager.GetRelatedEnd("WindowsFormsApplication.Models.MyPocoSubSet_MyPOCO", "MyPocoSubSet_MyPOCO_Source"))
{
// EXCEPTION
throw new InvalidOperationException("The property 'MyPocoSubSets' on type 'MyPOCO_A78FCE6C6A890855C68B368B750864E3136B589F9023C7B1D90BF7C83FD291AC' cannot be set because the collection is already set to an EntityCollection.");
}
base.MyPocoSubSets = value;
}
}
As you can see that exception raised in proxy class in ExtityFramework 5. This means that behavior still exist.

Entity Framework 4, MOQ,

I am using EF4, Microsoft.Entity.CTP, and the latest MOQ. I am trying to create a generic repository class and moq the DBContext using MOQ. Whenever I run my moq test I get "object reference not set to an instance of an object" on this.context.Set().Add(entity); and I don't understand why. The code runs ok without a moq.
public class GenericRepository<TEntity> : IGenericRepository<TEntity> where TEntity : class
{
private IContext context;
public GenericRepository(IContext context)
{
this.context = context;
}
public IList<TEntity> List
{
get { return context.Set<TEntity>().ToList(); }
}
public void Create(TEntity entity)
{
this.context.Set<TEntity>().Add(entity);
this.context.SaveChanges();
}
}
var mock = new Mock<IContext>();
GenericRepository<Product> producRepository = new GenericRepository<Product>(mock.Object);
mock.Setup(x => x.Product.Add(productType));
mock.Setup(x => x.SaveChanges());
productRepository.Create(product);
mock.VerifyAll();
You need to mock out the list implementation behind Set. I'm not at the compute ATM but iirc it's an IDbSet.
Change your code first definitions from DbSet to IDbSet and then you can mock them.
http://blogs.msdn.com/b/efdesign/archive/2010/06/21/productivity-improvements-for-the-entity-framework.aspx
I am considering changing my DbContext.tt file to generate IDbSet instead of DbSet, but only after I get the mocking to work.
I am not saying this makes the rest of the work easy, but it will get you past one problem.
What I need help with is what to do after changing my code first definitions to be based on the EF DbContext interfaces. For example, I create instances of my DbSet objects and add them.
Mock<IPosManContext> posManContext;
posManContext.Object.Set(typeof(note_template));
posManContext.Object.note_template.Add(
new note_template()
{
note_template_id = 1,
act_flag = "Y",
desc_text = "Monday Monday",
last_update_dtm = now,
last_update_user_id = "hsimpson",
});
But I get an error that the DbSet is null.
Microsoft needs to provide a good example of what to do.
They went half the way by providing public interfaces for mocking, but I still need more help.
Joe

Entity Framework and Entity Tracker Problems

If I run the following code it throws the following error:
An entity object cannot be referenced by multiple instances of IEntityChangeTracker
public void Save(Category category)
{
using(var db = new NorthwindContext())
{
if(category.CategoryID == 0)
{
db.AddToCategorySet(category);
}
else
{
//category.RemoveTracker();
db.Attach(category);
}
db.SaveChanges();
}
}
The reason is of course that the category is sent from interface which we got from GetById method which already attached the EntityChangeTracker to the category object. I also tried to set the entity tracker to null but it did not update the category object.
protected void Btn_Update_Category_Click(object sender, EventArgs e)
{
_categoryRepository = new CategoryRepository();
int categoryId = Int32.Parse(txtCategoryId.Text);
var category = _categoryRepository.GetById(categoryId);
category.CategoryName = txtUpdateCategoryName.Text;
_categoryRepository.Save(category);
}
I'm still learning Entity Framework myself, but maybe I can help a little. When working with the Entity Framework, you need to be aware of how you're handling different contexts. It looks like you're trying to localize your context as much as possible by saying:
public void Save(Category category)
{
using (var db = new NorthwindContext())
{
...
}
}
... within your data access method. Did you do the same thing in your GetById method? If so, did you remember to detach the object you got back so that it could be attached later in a different context?
public Category GetById(int categoryId)
{
using (var db = new NorthwindContext())
{
Category category = (from c in db.Category where Category.ID == categoryId select c).First();
db.Detach(category);
}
}
That way when you call Attach it isn't trying to step on an already-attached context. Does that help?
As you pointed out in your comment, this poses a problem when you're trying to modify an item and then tell your database layer to save it, because once an item is detached from its context, it no longer keeps track of the changes that were made to it. There are a few ways I can think of to get around this problem, none of them perfect.
If your architecture supports it, you could expand the scope of your context enough that your Save method could use the same context that your GetById method uses. This helps to avoid the whole attach/detach problem entirely, but it might push your data layer a little closer to your business logic than you would like.
You can load a new instance of the item out of the new context based on its ID, set all of its properties based on the category that is passed in, and then save it. This costs two database round-trips for what should really only need one, and it isn't very maintainable.
You can dig into the context itself to mark the Category's properties as changed.
For example:
public void Save(Category category)
{
using (var db = new NorthwindContext())
{
db.Attach(category);
var stateEntry = db.ObjectStateManager.GetObjectStateEntry(category);
foreach (var propertyName in stateEntry.CurrentValues.DataRecordInfo.FieldMetadata.Select(fm => fm.FieldType.Name)) {
stateEntry.SetModifiedProperty(propertyName);
}
db.SaveChanges();
}
}
This looks a little uglier, but should be more performant and maintainable overall. Plus, if you want, you could make it generic enough to throw into an extension method somewhere so you don't have to see or repeat the ugly code, but you still get the functionality out of it.