Entity Framework: Model doesn't reflect DB - entity-framework

I'm probably thinking about this all wrong but I have the following db tables:
When I run the EF Wizard in VS2008 I get the following model:
You'll notice that in the EF model shows that the Entity has no field for EntityTypeID or EntityStatusId. Instead it shows it as a navigation property, so the field appears to not be addressable when I instantiate an Entity (pardon the terminology confusion: Entity is a Table/Class in my name space not in the EF namespace). How can I assign an EntityTypeID and StatusTypeID when instantiating an Entity?

Yes, the entity framework hides foreign key ID properties and shows navigation properties instead. There is a lengthy discussion about why it does that, here. The usual means of assigning a reference to another entity is to assign the entity instance, rather than the foreign key ID value, like this:
var foo = new Entity();
var status = (from .... select ...).FirstOrDefault();
foo.StatusCodes = status;
However, it is possible to assign a foreign key ID directly, if you happen to know what it is:
foo.StatusCodesReference = new EntityKey(
"MyEntityContextName.StatusCodesEntitySetName", "StatusCodeId", value);
Obviously, substitute the real values in the above.

Related

EF cannot insert entity because key value for {'Id'} is already being tracked

I'm trying to write some tests around my Entity Framework code, an as part of the isolation of logic, I'm inserting a model into the database like this:
_context.Database.ExecuteSqlInterpolated(
$#"INSERT INTO MyModel(Id, Name, PostTown)
VALUES({Id}, {myModel.Name}, {myModel.PostTown});");
I have several tests based around reading this entity using _contest.Set<MyModel>().Find() which all work as expected.
I'm now trying to write a test to ensure my update methods work, the test looks something like this:
MyModel myModel = new Model("AName", "ATown");
_context.Database.ExecuteSqlInterpolated(
$#"INSERT INTO MyModel(Id, Name, PostTown)
VALUES({myModel.Id}, {myModel..Name}, {intermediary.PostTown});");
...
_context.Set<MyModel>.Update(myModel);
await _context.SaveChangesAsync();
However the update fails with an error:
The instance of entity type 'MyModel' cannot be tracked because another instance with the same key value for {'Id'} is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the conflicting key values.
Do I need to do something after my SQL insert to get EF to recognise the entity?

Marking navigation property as modified in Entity Framework 7

I have an EF7 DbContext with disabled change tracking because I want to mark all changes explicitly:
var entry = context.Entry(changedEntity);
entry.Property(propertyName).IsModified = true;
This works exactly as I want it to.
However, this does not work when a reference (navigation property) has been updated.
For example, let's say my entity has two properties - ParentId and Parent where ParentId is a foreign key and Parent is the reference to the parent entity.
Calling
entry.Property("Parent").IsModified = true;
does not work and throws ModelItemNotFoundException because Parent is not a property of the entity in terms of EF (it is a navigation instead).
In EF6, this could be done as follows:
var reference = context.Entry(changedEntity).Reference("Parent");
reference.CurrentValue = reference.CurrentValue;
IN EF7, there is no such function. I can get to the INavigation object with
entry.Metadata.GetNavigation("Parent")
but cannot see any way to mark it as modified.
So, how should I do it?
Note:
I know that setting ParentId would work, but this is not suitable for me because the referenced entity does not have ID yet as it has just been created and will get its ID from database when saved. Thus, I need to set it through the reference Parent.
Edit:
The note above was true for EF6 but is no longer valid for EF7 which I was not aware of. Thus, the solution is just as described in the note and answer below.
Wow, it seems that when a new entity is attached to the DbContext, it actually gets ID (-1 in my case). So, I can set ParentId even when the target entity is new and has not been added to the database yet.
I wonder whether there are any checks that the new ID is unique (there could already be an entry with ID -1 in database).

EF anonymous object query returns null collections instead of empty ones

I'm using this trick to perform conditional Include's with EF. http://blogs.msdn.com/b/alexj/archive/2009/10/13/tip-37-how-to-do-a-conditional-include.aspx
The problem I'm having is that any collections that don't have records, are null, and not empty. This is causing headaches cos I have to check each collection before I can loop through it in my mvc view, otherwise i get a null reference exception.
For example, the StudentModules collection will be null. How can I turn it into an empty list in my query? ie without having to loop through it all and checking.
I can put a constructor in the poco to initialize the list, which fixes it, but the this collection is a virtual member in the poco (based on an EF video!) - surely this is not the way to go?
var query = from module in db.Modules
where module.Id == id
select new
{
module,
QualificationModules = from qualificationModule in module.QualificationModules
where qualificationModule.IsDeleted == false
select new
{
qualificationModule,
qualificationModule.Qualification,
StudentModules = from studentModule in qualificationModule.StudentModules
where studentModule.IsDeleted == false
select new
{
studentModule,
studentModule.Student
}
},
Assessments = (from assessment in module.Assessments
where assessment.IsDeleted == false
select new
{
assessment,
assessment.AssessmentType
}
)
};
var modules = query.AsEnumerable().Select(x => x.module);
return modules.ToList().First();
Relationship fixup runs when an entity gets attached to a context - either manually by calling Attach or when the entity is materialized as a result of a query (your case).
It is based on foreign keys of an entity and works in both directions:
If the context already contains an entity A with a foreign key f to entity B and an entity B is being attached to the context that has a primary key with the same value f as the foreign key in A (i.e. the two entities are related by an FK relationship) then Entity Framework will do the following:
If A has a navigation reference property to B it will assign the attached entity B to this property.
If B has a navigation reference property to A (one-to-one relationship) it will assign A to this property.
If B has a navigation collection property to A (one-to-many relationship) it will add A to this collection in the attached entity B. If the collection is null it will instantiate the collection before adding.
If an entity B is being attached to the context that has a foreign key f to an entity A that the context already contains and that has f as primary key EF will set the navigation properties based on the same rules like above.
As a side note: The fact that relationship fixup is based on foreign keys (they are always loaded when you query an entity, no matter if the FK is exposed as property in the model class or not) is also the reason why relationship fixup does not apply to and does not work for many-to-many relationships because the two entities of a many-to-many relationship don't have a foreign key.
Now, if there are no related StudentModules in your case there is no StudentModule entity that gets loaded into the context and there is nothing what EF could target for a fixup. Keep in mind that the fixup algorithm is not related to a particular query and does not only fix relationships between entities that this query would materialize but it will consider all entities for fixup that the context already contains, no matter how they came into the context. If you would want that collections get instantiated as empty collections EF had run through all attached parent entities of StudentModules and just create an empty collection. It makes no sense to do this during fixup instead of creating empty collections up-front before entities get attached to a context.
I can put a constructor in the poco to initialize the list, which
fixes it, but the this collection is a virtual member in the poco
(based on an EF video!) - surely this is not the way to go?
In my opinion it is the best solution if you don't want to have null collections in your model class instances. It doesn't matter if the collection is declared as virtual (to enable lazy loading) or not. A collection type does not have a derived proxy type, only the instances that get added to the collection are derived proxies. In both case you can just use StudentModules = new HashSet<StudentModule>(); (or List if you prefer).

How should I deal with an EF code first model where no entities have keys?

I have used the Entity Data Model Wizard to generate an EF data model (an edmx with POCO's) based on the Object Catalogue Views in SQL Server, i.e. sys.objects, sys.tables, sys.columns, etc. When I try to access any data through my DbContext's DbSet properties, EF throws a ModelValidationException, complaining that entities don't have keys defined.
I can easily modify the T4 template that generates the entity POCOs to include a dummy property marked with the [Key] attribute, but this seems a bit klunky, as now my entity classes have a 'phantom' property that doesn't belong to them. Choosing a name for the key column is also an issue, but I could do something like generate a GUID for a unique key column name for ever class.
But, isn't there a better, neater way of telling EF I don't need key columns, as this model is strictly read only?
ADDENDUM: If I use the Entity Framework Power Tools - Reverse Engineer Code First tool, it creates a mapping class (derived from EntityTypeConfiguration) for each entity, and where the entity has no define key, it defines one using all the fields in the entity.

Mapping one to one foreign key relationships in Entity Framework 4.0?

I'm sure I'm missing something very simple, but let's say I have two entities, Employee and EmployeeType.
Employee type would contain values like 'Full time', 'Contractor', 'Intern', etc.
An Employee entity would contain one, and only one EmployeeType value.
So I am designing a new .edmx model using the Model-First approach and generating my actual sql server data schema from the model.
I want to add an integer type foreign key id into my Employee entity, EmployeeTypeId, which will map to the primary key of the EmployeeType entity.
So I've gone ahead and done that in my Employee entity. Where I'm stuck is how, though the Entity Framework designer, to enforce the 1:1 referential constraint on that EmployeeTypeId property? Or does the EF handle that automatically behind the scenes?
thanks in advance,
John
Think I figured out the answer to my own question. In the EF .edmx surface designer, I needed to right click on the scalar property I wanted to set as a foreign key id to the other entity and choose 'Entity Key'.
Once that was done, I could go into the referential constraints dialog box and point my new foreign key property to the other entity.
If you don't explicitly set your foreign key property as 'Entity Key', EF will think you want to point your primary key id to the other table.
cheers
You first create a new association (if you haven't done this already) between the two entities. Just right-click on the edmx designer and choose Add -> Association.
When you click on the association you have just created in the model designer, in the properties window, you can set the End1 Multiplicity and End2 Multiplicity properties to 1. This will ensure that you can set only one relation entity while using the entity framework. This does not get enforced in SQL server by the way, because SQL server does not implicitly support 1:1 relationships.