Include primary key of reference table in model using NHibernate - c#

We are using NHibernate for DB operations and in our database there is a reference of Organisation in the Configuration table. This is existing code and cannot be changed.
Configuration table is heavily used throughout application so we want to include the OrganisationId in the Configuration model class, but not in table as it already has reference object. By doing this we will avoid loading whole organisation object when we just need OrganisationId.
//Configuration.hbm.xml
<many-to-one name="Organisation"
class="Organisation"
not-null="false"
foreign-key="FK_ConfigurationItem_Organisation"
unique-key="UniqueConfigurationItemName"/>
//Configuration.cs (Model Class)
public virtual Organisation Organisation { get; set; }
How do I modify hbm or model class so that we get organisationId without including this field in table?
I am new to NHibernate and stuck with this requirement.
Any suggestion will be appreciated.
Thanks

it should not be necessary to try this optimization manually, because NHibernate has multiple options to handle that on it's own, and that methods work especially well for heavily used object (aka. rows). If you use a session-object with a cache NHibernate will prefere to access the cache (aka. memory) and not load from the database (a second, third or ... time). If you use eager or join-loading then NHibernate will include simple foreigen keys in the first sql to the database, a much quicker way then lazy-loading (only bad if he foreigen key is never accessed).
BUT
This is a bit of a guess and I am not 100% sure that it is the intended way to do it, but I accidentally mapped a column twice and you could do that too for the organisation, once as a foreigen key and once as a simple column (of witch ever type organisationid is).
Make sure that the setter of the "simple column" property is not public!
Make sure to update the "simple column" in the setter of the foreign key.
Greetings
Juy Juka

Related

Entity Framework, database wide Guid table, insert order

We have a synchronization framework that uses a global SyncEntity table to keep track of which entities have been updated at what time, meaning we have a global table with a structure something like this:
<dbo.SyncEntity>
ID int
EntityType int
EntityGuid uniqueidentifier
The EntityType is an enum that corresponds to the specific entity so that we know in which table to look for this entity.
All our tables have an ID (PK) and a GUID.
I have created a Foreign Key constraint from the different Entity tables and to the EntityGuid in the SyncEntity table.
This works perfect for existing data however when we use EntityFramework to insert new data it doesnt insert the data in the "correct" order resulting in an error because the SyncEntity with the required EntityGuid is not yet inserted.
I guess we could add a property SyncEntity on all of our entities however i really dont want to pollute our domain model with that property.
So my question, is there anyway to ensure that specific Entity types are inserted as the first entities?
Or is there anyway to map the relation from Guid (on the specific Entity) to EntityGuid (on SyncEntity) without a navigation property.
I see two ways you could potentially alleviate this issue.
First, you could use domain events to recognize that a new entity has been created and raise an event, passing in the entity itself as a parameter and then allow that event to create a new SyncEntity insert it and then save it. This will populate your ID and then you can assign it to the new entity creating the relationship.
Second, you could override the SaveChanges method of the DbContext to look at added entities and then create a new record for each of them, then assign your new SyncEntity Ids to the entity.
WHy would you bother EF with something like that?
Have the SyncEntity entry created by a trigger on the tables. Finished. EF does not have to bother with it.
And it is save for direct SQL usage, too.
EF is a good tool - though only a very very mediocre ORM. But it is not a solution for everything. DB internal logic, like a logging table, should be handled in the database.

DbContext with read-only set properties

I was reading this article http://blogs.msdn.com/b/adonet/archive/2011/01/27/using-dbcontext-in-ef-feature-ctp5-part-2-connections-and-models.aspx and was trying to figure out how to create private setters (the section in the article DbContext with read-only set properties is right before the summary). How would you create private setters? I was playing around with different methods but nothing seemed to work. I am doing this because I need to group the original table based on a query I have because the original table is a heap and I need a primary key for the entity. So anytime a client asks for this table it is already grouped. Not even sure if this is the correct way to do that. Thanks.
EDIT: sorry for being vague. I am doing code first. For example there exists a SQL Table with JobNbr, Qty and Date and I need to group by JobNumber, sum on Qty and take the oldest expiration date, and that will be my entity since this table has no primary key. The way I am doing it now gives me the error below from a method I created in the DbContext class. I do have a EntityTypeConfiguration class. Do I do this in that class?
EDIT: : you might be wondering why I am doing this. Basically I need to get data from the heap and save it in another database. My original approach was database.SqlQuery() to get grouped rows from the heap, but sometimes I have too many parameters for execute_sql. So I decided to create an entity for the grouped query without tracking changes (since all I am doing is reading from the table and saving to another DB). See my post here with the issue I am having https://stackoverflow.com/questions/22106030/entity-framework-6-this-database-sqlquery-character-limitation-with-sp-executes. The only way I know to get around it is to create an entity (even though in this case the entity is a query and not a table).
The entity or complex type
' cannot be
constructed in a LINQ to Entities query.

NavigationProperty null on added foreign key

Whenever I add a foreign key entity to my previous entity by setting the ForeignKey-ID, the associated object is null.
Let me explain this:
In a previous step I've set the AddressId property to 28 and have saved the entity context by calling context.SaveChanges().
Now why is AddressId filled, but Address as the NavigationProperty (which should be an Address object of the Address table where Address.Id == 28) is null?
Entity Frameworks (EF) work this by design.
Updating the foreign key never updates the navigation property.
However, updating the navigation property will update the key. Also note that in this case the Address entity should come from the same context. If not .SaveChanges() will consider the Address entity as new and try to add it in the database.
As to the question of which method is better, well, it depends!
- Updating the Key is straightforward and is what we have been doing all along using Data Transfer Objects (DTOs) or even plain SQL. So is easier for newcomers to EF to grasp and use.
- Updating the navigation property is where you truly get an object based data model. The code looks cleaner and more readable. However you need to be very careful with the Context. In my little personal experience with EF, I find that trying to update the navigation property brings more complexity than value, especially in a multi-tier architecture where the Context is hidden behind the Data Access layer.
The most important benefit of EF, in my opinion, is in query operations using LINQ-to-Entities. I have compile-time syntax check for my queries and strong typing. I can easily create an object-based result set with multiple levels of children, data-bind ready without any additional code. I rarely write SQL anymore.
I sorta fixed this by re-creating my entities and reloading then. This seems to work and re-fetch the n:m relationship navigation properties. Weird.

How can I denormalize my clr entity, but keep my db tables normalized?

I have these two related tables Client (ClientId, Name) and ClientDescription (ClientDescriptionId, (FK) ClientId, Description). That is to say each Client can have many associated descriptions. Now, when displaying the a list of ClientDescriptions, I also need to know what the Name of it's associated Client is.
Now you'll probably say that I allready have this information, since I can simply follow my navigation property back to the associated Client and use its Name. I can't do that because I'm autogenerating a grid in Ria services, and this just gives me a count for navigation properties, and I haven't found a way to flatten this down in my metadata file. Hence why I want a property.
The whole idea is that I want to be able to add a new field to my database, update my entity classes from the database and regenerate my domain service, and the new field should just pop up in my grid. I shouldn't have to update my xaml just because my database happen to have an extra field.
So, what I would like to do is add a ClientName field to the entity (clr object), but keep my database clean (no such denormalization in the db).
So, I generated my edmx, and added a new property named ClientName. Set it to StoreGeneratedPattern.Computed, and compiled. I then get a nasty little error
Error 3004: Problem in mapping fragments starting at line NN: No mapping specified for properties (etc..)
The solution apparently is to generate my database from my edmx. (Or that's what answers to questions about that error seems to yield.) But this generates an actual DB-field, which I don't want, so that answer doesn't apply to my case.
So my question is: How can I denormalize my clr entity, but keep my db tables normalized?
Edit: I guess this question can be generalized a bit. The issue would be the same if ClientDescription contained a few numeric fields that I wanted to do some calculations on, and I wanted the result available as a field and the algorithm should be in c# rather than in my database.
To answer your more generalized question:
Entities are generated by the Entity Framework with a partial keyword.
This means that the code of an entity can be split in multiple source files in the same namespace and assembly. One will contain the generated code from the Entity Framework, the other will contain custom properties and methods.
If for example, your entity has the database fields Price and Amount you could add a property in the partial class TotalPrice which would return Price * Amount.
Then the algorithm will be C# and your database won't know about the extra property.

Entity Framework 4 Table Per Hierarchy - How To Define Navigational Properties On Children?

I currently have a Entity Framework 4.0 model in place with Table Per Type (TPT), but there are a few performance issues (lots of LOJ's/CASE statements), as well as an issue mapping between two particular domain areas (many-to-many).
I've decided to try out TPH.
I have an entity called "Location" which is abstract, and the base for all other entities.
I then have "Country", "City", "State", "Street", etc which all derive from Location.
"LocationType" is the dicriminator.
That part is working fine, but i'm having issues trying to define navigational properties for the derived types.
For instance, a "State" has a single "Country", so i should be able to do this:
var state = _ctx.Locations.OfType<State>().Include("Country").First();
var countryForState = state.Country;
But this would require a navigational property called "Country" on the "State" derived entity. How do i do this? When i generate the model from the database, i have a single table with all the FK's pointing to records in the same table:
(NOTE: I created those FK's manually in the DB).
But the FK's are placed as nav's on the "Location" entity, so how do i move these navigational properties down to the derived entities? I can't copy+paste the navs across, and i can't "create new navigational property", because it won't let me define the start/end role.
How do we do this?
It's also not clear with TPH if we can do it model-first, or we HAVE to start with a DB, fix up the model then re-generate the DB. I am yet to find a good example on the internet about how to define navs on children with TPH.
NOTE: I do not want to do code-first. My current solution has TPT with the EDMX, and pure POCO's, i am hoping to not affect the domain model/repositories (if possible), and just update the EF Model/database.
EDIT
Still no solution - however im trying to do model-first, and doing Add -> New Association, which does in fact allow me to add a nav to the derived entities. But when i try and "Generate database from Model", it still tries to create tables for "Location_Street", "Location_Country" etc. It's almost like TPH cannot be done model first.
EDIT
Here is my current model:
The validation error i am currently getting:
Error 1 Error 3002: Problem in mapping
fragments starting at line
359:Potential runtime violation of
table Locations's keys
(Locations.LocationId): Columns
(Locations.LocationId) are mapped to
EntitySet NeighbourhoodZipCode's
properties
(NeighbourhoodZipCode.Neighbourhood.LocationId)
on the conceptual side but they do not
form the EntitySet's key properties
(NeighbourhoodZipCode.Neighbourhood.LocationId,
NeighbourhoodZipCode.ZipCode.LocationId).
Just thought i'd keep editing this question with edit's regarding where i am currently at. I'm beginning to wonder if TPH with self-referencing FK's is even possible.
EDIT
So i figured out the above error, that was because i was missing the join-table for the Neighbourhood-ZipCode many to many.
Adding the join table (and mapping the navs to that) solved the above error.
But now im getting this error:
Error 3032: Problem in mapping
fragments starting at lines 373,
382:Condition members
'Locations.StateLocationId' have
duplicate condition values.
If i have a look at the CSDL, here is the association mapping for "CountyState" (a State has many counties, a County has 1 state):
<AssociationSetMapping Name="CountyState" TypeName="Locations.CountyState" StoreEntitySet="Locations">
<EndProperty Name="State">
<ScalarProperty Name="LocationId" ColumnName="StateLocationId" />
</EndProperty>
<EndProperty Name="County">
<ScalarProperty Name="LocationId" ColumnName="LocationId" />
</EndProperty>
<Condition ColumnName="StateLocationId" IsNull="false" />
</AssociationSetMapping>
It's that Condition ColumnName="StateLocationId" which is complaining, because ZipCodeState association also this condition.
But i don't get it. The discriminators for all entities are unique (i have triple checked), and i would have thought this was a valid scenario:
County has a single State, denoted by StateLocationId (Locations table)
ZipCode has a single State, denoted by StateLocationId (Locations table)
Is that not valid in TPH?
So i solved a few of my issues, but i hit a brick wall.
First of all, when you create self-referencing FK's in the database side, when you try and "Update Model from Database", Entity Framework will add these navigational properties to the main base type, as it has no explicit sense of TPH - you need to do this in the model side.
BUT, you can manually add the navigational properties to the child types.
WRT this error:
Error 3032: Problem in mapping fragments starting at lines 373, 382:Condition members 'Locations.StateLocationId' have duplicate condition values.
That was because i had an FK called "Location_State" which i was attempting to use for the "ZipCode_State" relationship, AND the "City_State" relationship - which does not work (still no idea why).
So to solve that, i had to add extra columns and extra FK's - one called "ZipCode_State", and another called "City_State" - obviously it has to be a 1-1 between navs and physical FK's.
Location.LocationType has no default value and is not nullable. A column value is required to store entity data.
That is my discriminator field. In the database side, it is not nullable.
I read threads about this issue, and they said you need to change the relationships from 0..* to 1..* - but my relationships already were 1..*.
If you look at my "Locations" actual database table above, all the FK's are nullable (they have to be). Therefore i started wondering if my relationships should be 0..*.
But they are nullable because of the TPH - not all "Locations" will have a "State". But if that Location is a "City", then it HAS to have a "State".
My feelings were further comforted by this SO question: ADO EF - Errors Mapping Associations between Derived Types in TPH
I was actually trying that workaround (before i even came across it), and the workaround does not work for me. I even tried changing all the relationships from 1..* to 0..*, and still no luck.
Wasting too much time here, I've gone back to TPT.
At the end of the day, with TPH i would have had a ridiculously large table, with lots and lots of redundant, nullable columns. JOIN-wise, it's more efficient. But at least with TPT i am not required to have nullable and self-referencing FK's.
If anyone has a solution to this problem, let me know. But until then, im sticking with TPT.

Categories