Entities fetched as ReadOnly in NHibernate are present in PersistenceContext - c#

I'm working on a project which uses NHibernate as an ORM.
A fairly large number of entities can be loaded into the session as 'readonly' since they should not be updated after retrieval.
I've tried to do this in 2 different ways:
var entity = criteria.UniqueResult<MyType>();
_session.SetReadOnly(entity, true);
or:
criteria.SetReadOnly(true);
In both ways however, I can see that the entity is present in the PersistenceContext of the ISession.
Is this normal ? I'd expect that, since the entity is readonly/immutable, it should not be present in the PersistenceContext.
The entity type is a complex type; it has multiple associations to other types.

There are some limitations to the Read-Only functionality in nhibernate. The name of the function lets one expect a harder warranty of preventing object changes.
If you look at the documentation (http://nhibernate.info/doc/nh/en/index.html#readonly) there are many exceptions that could lead to unintended changes in the database.
From the docs:
When an entity is read-only:
NHibernate does not dirty-check the entity's simple properties or
single-ended associations
NHibernate will not update simple properties or updatable
single-ended associations
NHibernate will not update the version of the read-only entity if
only simple properties or single-ended updatable associations are
changed
In some ways, NHibernate treats read-only entities the same as entities that are not read-only:
NHibernate cascades operations to associations as defined in the
entity mapping.
NHibernate updates the version if the entity has a collection with
changes that dirties the entity;
A read-only entity can be deleted.
Considering your expectations it think Objects are always added to the Persistence-Context even if they are load Read-Only. Otherwise the Identity-Map -Pattern would not hold. In the Persistence-Context there is a Flag that signals that an entity is Read-Only.
In the context the state can be checked by opening the individual entity entry.

Related

EF Include() between contexts?

I have two extended instances of DbContext that I use in my code-first solution. One is only ever read only as it maps to an existing set of tables for demographic purposes. The other context is mapped to a local working set of tables.
I have created a view and mapped it to its own entity that is included as a navigational property in a POCO model representing an entity that's mapped to the other context. So my question is: can I use Include to fetch related entities across contexts? So far this doesn't appear so as it complains that it's looking for the view under the wrong schema - the one used for the other context - even though the view clearly has the correct schema defined in its mapping.
I'm using EF 6 with MVC 4.
Each context runs in complete isolation and you cannot share objects from one context to the other. Even if you pull the objects from the database in notracking mode, the moment you associate those objects in the other context by assigning them to navigation properties you are effectively pulling them into the other context which you don't want.
If you have a readonly context of some kind then what you can do is only fill in the foreign keys ids in the read/write context.

Can entities be deleted without the ObjectContext?

Using the default code generated entities with Entity Framework, is there a way to delete an entity object without using the ObjectContext? For example, self-tracking entities have a MarkAsDeleted method. Also, the ObjectContext isn't needed to update or add objects, so I'm hoping the same applies to deleting objects.
One thing that doesn't work is to simply mark the entity as deleted since the property is readonly:
foo.EntityState = EntityState.Deleted;
Answer seems to be no, so I'm using a technique I wrote about before to attach the ObjectContext to all entities that need to delete child entities: http://sixfeetsix.blogspot.com/2012/06/provide-entityobjects-access-to-their.html

Generic method for comparing 2 objects and update changes from one to the other in c#

Problem case:
My problem is editing disconnected POCO entities and then saving them to the database (Uisng Entity Framework). When doing so, the generated sql updates ALL properties even though only some have actually changed. When I do the same within the context, the generated sql correctly updates only the modified properties. This causes problem with my auditing code since it wrongly stores changes on all the properties. This is made worst when the entity I am persisting has a complicated model with many relationships.
My proposed solution:
Instead of attaching the modified entity to the context, I want to query the entity and then manually syncronize the two object with a generic method that will work for any model. So I need to compare all properties from each object and update the modified properties to the attached entity. How do I go about updating the values in the properties, keeping in mind that changes might include new or modified relationships ?
Any thoughts?

Entity Framework - Inserting entity with multiple models and databases

I have my domain split into multiple Entity Framework models. I have some shared entities that span multiple models (named Lookup), however, these are replaced with "using" references using the methods described in Working With Large Models In Entity Framework. However, what makes my case slightly more unique is that I'm also separating these models into multiple databases (one per model).
I'm having a problem inserting one of my shared entities into my common DB. It's failing with the error:
The member with identity
'Harmony.Members.FK_ResidentialAddress_ResidenceTypeLookup'
does not exist in the metadata
collection.
That foreign key that it's referring to does not exist on the "common DB". But I'm also not working with the entity on the other side of the relationship (named ResidentialAddress); nor do I even have the context that would contain the other entity initialized (named MembersDb). However, both models are compiled into the same assembly.
There are no navigation properties going from Lookup to ResidentialAddress. Though there is a navigation property in the other direction (which I won't be persisting - only using in memory).
My MetadataWorkspace for the EntityConnection of the CommonDb context was explicitly initialized with only the SSDL/CSDL/MSL for the data required for that database. I have confirmed there is no references to the foreign key mentioned in that set of schema data.
var metaAssembly = typeof(CommonDb).Assembly;
var schemaResources = new string[]
{
String.Format("res://{0}/Common.ssdl", metaAssembly.FullName),
String.Format("res://{0}/Common.csdl", metaAssembly.FullName),
String.Format("res://{0}/Common.mdl", metaAssembly.FullName),
}
MetadataWorkspace metadata = new MetadataWorkspace(schemaResources, new []{ metaAssembly });
EntityConnection connection = new EntityConnection(metadata, myDatabaseConnection);
POSSIBLE CLUE: It does work when I go into the generated classes and remove all of the EdmRelationshipAttribute attributes along with their paired EdmRelationshipNavigationPropertyAttribute from the related models (MembersDb).
Key questions:
So why is it that Entity Framework is trying to do something with the relationship that is for an entity that is neither in scope and nor will it be affected by the insertion of the record!?
I am happy to have the generated code remove the attributes mentioned above, but I still want the navigation properties to remain. How would I go about altering the CSDL to achieve that?
NOTE: Persistence of the "child" models is not a priority, nor is the integrity of their now cross-DB foreign keys. These databases are persisted using SQL CE but they were originally generated from a single master SQL Server database.
If each part of your model is written to a separate database, then perhaps the edmx files should not know about each other (about entities or relationship to entities that do not belong to them).
How about trying one of the following approaches:
(To end up with same entities classes for each part, but make EF oblivious of connections between them.)
Remove the "usings" from edmx + cancel auto generation and create classes yourself.
Remove the "usings" from edmx + modify t4 template to read more than one edmx when creating the classes.
Copy edmx files aside so you have two sets of edmxs.
3.a. Use set #1 for auto generation of entities.
3.b. Modify set #2 by removing the "usings" and use for generation of repository classes (objectsets).
Let me know if one of these works.
Good luck,
Danny.

Why is "Fixup" needed for Persistence Ignorant POCO's in EF 4?

One of the much-anticipated features of Entity Framework 4 is the ability to use POCO (Plain Old CLR Objects) in a Persistence Ignorant manner (i.e. they don't "know" that they are being persisted with Entity Framework vs. some other mechanism).
I'm trying to wrap my head around why it's necessary to perform association fixups and use FixupCollection in my "plain" business object. That requirement seems to imply that the business object can't be completely ignorant of the persistence mechanism after all (in fact the word "fixup" sounds like something needs to be fixed/altered to work with the chosen persistence mechanism).
Specifically I'm referring to the Association Fixup region that's generated by the ADO.NET POCO Entity Generator, e.g.:
#region Association Fixup
private void FixupImportFile(ImportFile previousValue)
{
if (previousValue != null && previousValue.Participants.Contains(this))
{
previousValue.Participants.Remove(this);
}
if (ImportFile != null)
{
if (!ImportFile.Participants.Contains(this))
{
ImportFile.Participants.Add(this);
}
if (ImportFileId != ImportFile.Id)
{
ImportFileId = ImportFile.Id;
}
}
}
#endregion
as well as the use of FixupCollection. Other common persistence-ignorant ORMs don't have similar restrictions.
Is this due to fundamental design decisions in EF? Is some level of non-ignorance here to stay even in later versions of EF? Is there a clever way to hide this persistence dependency from the POCO developer?
How does this work out in practice, end-to-end? For example, I understand support was only recently added for ObservableCollection (which is needed for Silverlight and WPF). Are there gotchas in other software layers from the design requirements of EF-compatible POCO objects?
Found a few explanations - check them out!
POCO Template Code Generation Options (EF team blog)
Fixup
A fixup method is written for every
navigation property on an entity and
is called from the setter of the
navigation property whenever its value
changes. Its purpose is to ensure that
each end of a bidirectional
relationship stays in sync with the
other. For example, in a one-to-many
relationship between Cutomer and
Order, whenever Order.Customer is set,
the fixup method ensures that the
Order is in the Customer’s Orders
collection. It also keeps the
corresponding foreign key property
viz. Order.CustomerID in sync with the
new Customer’s primary key (ID) value.
This logic can be useful if the POCO
entities are used independently of the
EF stack, like for writing tests
against them which don’t hit the
database. Fixup ensures that the
object graph is connected in the same
way as you would expect while using
them with EF. Fixup methods are a bit
complex to write and hence it is
useful to have them auto-generated if
you are planning on using the entities
in an EF independent scenario.
And also check out this POCO in the Entity Framework Part 1 which also has some sections on what fixups are and what they're needed for.

Categories