I'm working with a legacy database put together by some very strange people. I'm writing an NHibernate DAL over the top of it but running into some odd mapping scenarios.
In one example, I have a table with a number of fields including LE_RECNUM (integer primary key) and LE_CODE (string).
However, all relationships throughout the database join onto LE_CODE, not LE_RECNUM, for some unfathomable reason.
I need to specify that LE_RECNUM is the Id in my mapping file, because I need the primary key to be generated when I insert records. However, I want all associations to use LE_CODE instead of LE_RECNUM.
Can anyone suggest how I might do this?
References(x => x.SomeProperty).Column("LE_CODE").PropertyRef(x => x.SomePropertyInParent);
Related
Is there a way to map property with database column with custom column, that IS NOT a FK, just a candidate key ( it is unique for table )?
If not, what is my options here? (need to restrict select results with joined table restrictions)
NHibernate supports feature called property-ref. It is documented here: 5.1.10. many-to-one. Some extract:
The property-ref attribute should only be used for mapping legacy data
where a foreign key refers to a unique key of the associated table
other than the primary key. This is an ugly relational model. For
example, suppose the Product class had a unique serial number, that is
not the primary key. (The unique attribute controls NHibernate's DDL
generation with the SchemaExport tool.)
So, if the child table contains for example Guid, which is the same as in the target parent table... this could solve the issue. Example mapping:
<many-to-one name="Parent" property-ref="ParentGuid" column="THE_GUID_COLUMN"/>
Using the fluent syntax, it could look like this:
References(x => x.Parent)
...
.PropertyRef("ParentGuid")
.Column("THE_GUID_COLUMN");
Anyhow, this is not ideal and should be used mostly for solving legacy stuff.
I have 3 tables
Brands:
BrandID int
BrandName varchar(30)
Products
ProdID int
ProdName varchar(30)
BrandToProd:
BrandID int => FK Brands.BrandID
ProdID int => FK Products.ProdID
After generating model from existing database EF omits BrandToProd table and creates Many-To-Many relationships between Brands and Products. I would like to have third entity with following fields:
BrandName varchar(30)
ProductsName varchar(30)
This will give me possibility to use scaffolding for this entity. Ideally, when I'll add new pair of Brand and Product, EF should check first if such Brand or Product already exist in database (to avoid duplicates), if no, add to corresponding tables and that add mapping to BrandToProd table. If Brand or Product already exist, EF should you existing BrandID/ProdID value when adding to BrandToProd table. Is there any idea how to do that?
Your BrandToProd table is a pure junction table, i.e. a table with only two foreign keys. It is an EF feature to model such tables into a many to many association without a class in the conceptual model.
The easiest way to include a pure junction table in the model as an entity class is
add a dummy field to the database table temporarily
generate the model
delete the field from the database
update the model from the database
delete the property in the edmx diagram
An alternative way is to edit the edmx manually, but then you really need to know what you're doing. If you don't want to regenerate the model you could generate a second model and investigate the differences in both edmx files by a difference viewer.
However, I wonder if you need to do this. You seem to relate this to duplicate checking. But if you want to add a Brand or Product to the database you'll have to check for duplicates either way. If you want to add a new association (e.g. adding an existing Brand to Product.Brands) you don't have to check whether it exists. If it does, EF just ignores the "new" association.
As extra point to Gert's answer:
when using surrogate keys, there is always the issue of duplicate management. Normally there is 1 or more fields that make a logical key.
you can
a)create a unique index on the Db. Db will complain when the constraint is violated
b)Execute a logical duplicate check before attempting an insert.
I've ended up with just adding dummy ID field to my junction table, as I'm frequently changing DB schema (becsuse site development is in progress and I need from time to time update model from database) and don't want to each time remove/add dummy field to database. Another option I've used - SQL View on two tables and stored procedures mapped to corresponding actions (CRUD) in EF
I am using Fluent NHibernate (which I am fairly new to) in an application I am developing using a legacy Oracle DB. The DB has composite keys which are comprised of foreign keys and database generated columns. The generated columns are supplied by calling a DB function with the table name, and one of the other foreign key parts. The generated composite key parts are not unique, and I cannot change this. The generated key parts are often used as foreign keys on other tables too.
If I create entity mapping which specifies the composite key as it is in the database, then we cannot use any identity generation strategies, which breaks unit of work
If I create entity mapping which specifies only the generated column as the primary key, then I can use trigger-identity to generate the ids, and I get unit of work, but I then have a problem when I want to update, or access a child collection: The other parts of the key are not included in the WHERE statement.
Can anyone give me any advice on how to proceed?
If I stick with mapping composite keys, can I extend nhibernate to output the SQL to use trigger-identity? If so, can you suggest a starting point?
If I map a single column key, can I include other properties in a WHERE clause for HasMany mapping and Updates?
Unfortunately, as you have already found out, there is no support at all for this setup.
My suggestion is to do INSERTS manually (using custom SQL, for example). And yes, this breaks the UoW, but that is true of identity too.
I am trying to create a mapping to a database table that has no primary keys/references.
public class TestMap : ClassMap<<Test>Test> {
public TestMap() {
WithTable("TestTable");
Map(x => x.TestColumn);
}
}
This fails and expects id or composite-id. Is this possible in fluent nhibernate?
In Oracle at least, I have used "ROWID" for this. For mssql you might use the "ROW_NUMBER()" builtin function for readonly access to the table, but I haven't tried that...
No. You'll have to add a surrogate primary key, such as an identity column in SQL Server, to map this table. As far as I know, this isn't supported by NHibernate itself.
Why don't you have a primary key on this table?
This functionality isn't supported by nhibernate as far as I know. As a general rule of thumb, however, you should really always have some kind of ID and if you find yourself in a situation where you think you don't need one you should assess your data model. An ID, whether it be a table-specific primary key, or a surrogate key from another table, should exist. This not only ensures that nhibernate can process the table, but helps performance via indexing.
Before you start assuming nhibernate isn't going to fulfill your needs, consider why you don't have a key on the table and what kind of sense it makes not to have one.
If we can bring a column from table having no primary key/identity coulmn, then we can use fluent as below:
Id(x => x.TempID).Column("TempID");
If the table contains data that belongs to another entity, you could map it as a collection of components. Components are not identified by themselves, but they belong to another entity, which is identified.
You can map an entity to a table without keys defined in the database. I do so in legacy SQL Server databases. However, the table must have a candidate key (some set of columns that actually stores a unique combination of values). The concept of entity involves the notion of some kind of identity.
Instead of this, what you're trying in your code is to map an entity without identity, wich isn't possible.
I am just starting out with ADO.net Entity Framework I have mapped two tables together and receive the following error:
Error 1 Error 11010: Association End 'OperatorAccess' is not mapped. E:\Visual Studio\projects\Brandi II\Brandi II\Hospitals.edmx 390 11 Brandi II
Not sure what it is I am doing wrong.
I believe I can add some more clarity to the issue (learning as I go):
When I look at the Mapping details and look at the association, the column for operatoraccess table (from above) is blank and the drop down only includes field from the linked table.
The Entity Framework designer is terrible - I've had the same problem many times (and your problem too, Craig):
This happens when you have a many-to-one association which is improperly setup. They could very easily fix the designer to make this process simple; but instead, we have to put up with this crap.
To fix:
Click on the association, and go to the mapping details view.
Under association, click on Maps to <tablename>. Choose the table(s) which make up the many side of the relationship (ie. the table(s) which make up the *-side of the association in the designer)
Under Column, choose the table-columns which map to each entity-side Property. You get this error when one of those entries are blank.
I had the exact same problem and this is what I did to fix it.
Make sure you have an Entity Key set in your designer on the tables your making an association with. Also check that StoreGeneratedPattern is set to Identity for that Entity Key.
There's not a lot of information in your question, but, generally speaking, this means that there is an incompletely defined association. It could be that you have tried to map one table with a foreign key to another table, but have not mapped that other table. You can also get this error when you try to do table per type inheritance without carefully following the steps for implementing that feature.
Not sure of the answer, but I've just posted a similar question, which may at least help clarify the issue you are experiencing.
Defining an Entity Framework 1:1 association
I had to go back into the database itself and clarify the foreign key relationship
I had this problem in the case where I was creating both many to 0..1 and 0..1 to 0..1 associations. One entity needed associations to multiple tables, and that entity did not have foreign keys defined for those tables.
I had to do the table mappings step that is given in the accepted answer, but note that it wasn't only for many to many associations; it applied to all the types of associations I added for this entity.
In the Mapping Details view, I had to select the entity with the non-foreign key ID columns to the various tables. This is not always the "many" side of the relationship. Only there was I able to map the related entity property to the appropriate property in the original entity. Selecting the "destination" entity would not allow me to select the properties that I needed to, and the error would still exist.
So in short, I had to map using the table related to the entity that had the "non-foreign key" ID fields corresponding to the various entities' (and their tables') primary keys that I needed to associate.
Entity A
various other properties...
Id
ContactId
OrderId
etc.
Contact entity
Id
FirstName
LastName
etc.
In the mapping details, I selected Entity A's table. It then showed both ends of the association. I mapped its Entity A's Id property to its table's actual ID column (they had different names). I then mapped the Contact entity's Id field to the ContactId field on the A entity.
Simply select the many relationship table (*) from the Association>Edit Mapping & select the appropriate relationship