Entity Framework 6: Custom navigation without foreign key? - entity-framework

we are wondering, how it is possible with EF to define a custom navigation without a foreign key being necessary/ generated. Study case:
There shall be two objects, Funds and Prices.
2.1 A Fund can have many prices.
2.2 Prices are historic, the latest price is flagged.
The link between fund and prices is on the IsinCode, not the primary keys.
IsinCode and IsLatest are having a unique constraint (there can be only 1 price per isin being latest)
The sql would look like the following:
select * from Funds f
join Prices p on f.IsinCode = p.IsinCode and p.IsLatest=1
The closest we are able to setup in the EF model builder looks like the following:
modelBuilder.Entity<Fund>(e =>
{
e.HasOne(ex => ex.LatestPrice)
WithMany()
HasPrincipalKey(pk => pk.IsinCode) // not considering constraint IsLatest =1
}
--> this attempt brings the issue that EF wants either a unique key on IsinCode or a unique constraing (both fail)
A many-to-many relation brings the issue that we load way too much data to drop all but latest. Any idea how such a navigation can be expressed with EF?

Related

ASP.Net WebAPI OData - Composite keys on entities

I have some entities in my EF data model where the entity's key is a composite of two columns.
Made-up (but reasonably close) example... Three entities
Patients
PatientID (PK)
PatientName, etc
Identifiers
PatientID (PK)
IdentifierTypeID (PK)
Code
StartDate, etc
IdentifierTypes
IdentifierTypeID (PK)
Description
The Identifiers table has a composite key. Basically a many-to-many between Patients and IdentifierTypes but with data on the join table. It ought not to matter, but in case it does, the IDs are GUIDs (uniqueidentifier in SQL Server).
I can bend my database a bit to make a new column in Identifiers such as "IdentifierID" that could be the primary key, but we have a legacy code base I'd rather not modify if I can avoid it.
I can see several solutions that avoid modifying the tables although I'm not sure if all are actually possible in WebAPI
a)
Create a view in the database and have this as the basis of my entity. The view is of the form
select
*,
IdentifierID = cast( PatientID as varchar(50) ) + '_' + cast( IdentifierTypeID as varchar(50) )
from Identifiers
This has the problem that seeks on IdentifierID from Entity Framework will be slow. I can rectify this somewhat with an indexed view I suppose.
b)
Same as (a), but in my controller's [Queryable] Get() method I instead use ODataQueryOptions and some expression parsing magic (not very experienced with it at all) to see if we're filtering on IdentifierID and, if so, split that up into filters on PatientID and IdentifierTypeID
c)
I keep things as they are and discover some unknown support for Tuple as entity key in the WebAPI OData stack. That would be awesome :)
I'm inheriting from EntitySetController<>, so it would look like I'm inheriting from EntitySetController>
d)
Some blend of (c) that's not quite as clever but still achieves the same outcome
It seems possible to have composite keys in the OData spec as this other question on StackOverflow says how to address such an entity in OData (using WCF Data Services). How to address entity that uses composite identity key in OData Url?
I don't mind using nightly builds or even using the ASP.Net source - I've spent the weekend stepping through OData requests already to solve another issue (my fault) formatting GUIDs in query strings :P I'm hoping someone's already invested the hours understanding this and I can avoid another day hitting breakpoints in the framework source.
Thanks for your help,
Ian
It is possible to do composite keys with web API OData. You don't even need to use the nightly build to do that. RTM bits should be good. Refer to this great sample by Hongye for details.

Why can't I have a referential constraint with a one to zero-to-one association?

I'm using entity framework 4.3 model first and can't figure out why I'm not allowed to have a one to zero-to-one association along with a referential constraint.
I have two main problems. I can't force referential integrity (without manual intervention) and my lazy loading doesn't seem to work... all my 1 to many associations are fine.
I basically have two tables, Loans and Contracts. The Contracts table has a scalar field for LoanId.
Until a loan is submitted, it does not have contract data and I chose not to place everything in the same table due to the size of the contract data. Ie. I don't want contract data retrieved from the database unless it is actually required.
I've searched around and can't seem to find any model first information that clearly answers my questions. Any information that may help me understand and clarify my problem would be greatly appreciated.
Regards
Craig
I guess LoanId field is not a primary key in Contracts table. In such case you cannot have such one-to-one relation because EF doesn't support it. When you create LoanId field in Contracts table the only way to force one-to-one relation is to add unique constraint on that field. EF currently doesn't support unique keys (except primary keys) so the only way to create one-to-one relation is to create relation between primary keys (Loan.Id <-> Contract.Id). If you don't follow this you will get error in designer.

Is this possible to model a "foreign key" into multiple tables with Entity Framework?

I have a MS SQL 2008 database, and I can't change its schema. I have to work with what it is.
It has three tables that relevant to the question.
Product table. The columns are:
Id (identity, PK)
Group (NOT NULL)
SubGroup (NOT NULL)
Code (Unique, NOT NULL)
Description
Contract table. The columns are:
Id (identity, PK)
Code (NOT NULL)
Descritpion
Discount table. The columns are:
Id (identity, PK)
Type (restricted to one of the four values:
'product',
'group',
'subgroup' or
'contract') (NOT NULL)
Object (depending on the value of Type refers one of the four:
Product.Code
Product.Group
Product.SubGroup
Contract.Code) (NOT NULL)
Value (NOT NULL)
The idea is that the discount can be applied to either of the four. I'd like to reiterated, that this is the database design that I can't change.
With Entity Framework I can query the tables all right with joins but I can't use navigation properties out of the box, because navigation properties are generated based on foreign key relationships from database, and you can't define "conditional" relationship in MS SQL, where the field object relates to one table when field type contains this value and relates to another table when the value is different.
My question is this: Is this possible to define classes and mappings with Entity Framework, so that I can use navigation properties in this scenario? For example, I do Discount.Object and I receive either Contract object or Product object in response, and if this is a Product object it's retrieved on the right property.
Is this, or something similar possible, or joins is the best I can do?
You said that "this is the database design that I can't change", but without changing existing tables, can you at least add views?
If you can, you can create a view for the Discount table that has four different nullable columns for each relationship. That would map nicely in EF as four navigation properties.
After you do that, if you still want a combined column, you could add your own property to the Discount entity that will return an object by checking which of the four navigation properties is not null, and returning the linked entity.
You cannot create a relational database like this. You need separate columns for the keys to each potential parent row.

Trouble inheriting from another entity

I'm having trouble configuring entity relationships when one entity inherits from another. I'm new to ADO Entity Framework -- perhaps someone more experienced has some tips for how this is best done. I'm using .net 4.
Database tables with fields:
Products (int ID, nvarchar Description)
FoodProducts (int ProductID, bit IsHuge)
Flavors (int ID, int FoodProductID, nvarchar Description)
There are constraints between Products and FoodProducts as well as FoodProducts and Flavors.
Using the designer I create a model from the database. The designer seems to get it right, with a 1:0..1 association between Product and FoodProduct entities, and 1:* association between Flavor and FoodProduct. No errors when I save or build.
Next I set FoodProduct entity to inherit from Product entity. Then I get errors concerning relationship between Product and FoodProduct. Ok, starting fresh, I first delete the relationship between Product and FoodProduct before setting the inheritance. But now I get errors about the relationship between FoodProduct and Flavor. So I delete and then recreate that relationship, connecting Flavor.ID to FoodProduct.ProductID. Now I get other errors.
My question is this: Should I instead be creating relationship between Flavor.FoodProductID and Product.ID? If so, I assume I then could (or should) delete the FoodProduct.ProductID property. Since my database will have many of these types of relationships, am I better off first creating the entity model and exporting the tables to SQL, or importing the database schema and then making many tweaks?
My intent is that there will be several types of products, some of which require many additional fields, some of which do not. So there may be zero or one FoodProducts records associated with each Product record. At least by my thinking, the table for each sub-type (FoodProducts) should be able to "borrow" the primary key from Products (as a FK) to uniquely identify each of its records.
You can find a screen capture here: http://img218.imageshack.us/img218/9720/entityframework.jpg (I'd embed the img but haven't earned the requisite rep' yet!)
Well, I deleted the FoodProduct.ProductID field, as it should always return the same value as Product.ID anyway. Then, as you hinted, I had to manually map the Products.ID field to FoodProducts.ProductID field. Errors resolved. I'll write a little code to test functionality. Thanks for the "observations"!
Couple of observations:
FoodProducts needs a primary key (e,g identity - FoodProductID). Are you sure it should be a 1:0..1 between Food and FoodProducts? I would have thought it should be 1:0..*. For this cardinality to work you need a unique PK on this table.
When you setup inheritance for entities, the parent entity's properties are inherited. So FoodProducts will inherit ID from the Product table.
BUT, on the physical model (database), this field still needs to be mapped to a column on the FoodProducts table - which is why you need the identity field.
After you setup inheritance, you still need to map all the columns on the derived tables. My money is on you have not mapped "ID" on FoodProducts to any column.
If you screencapped your model and show the errors you are getting it would be much easier to diagnose the issue.

Entity Framework many-to-many question

Please help an EF n00b design his database.
I have several companies that produce several products, so there's a many-to-many relationship between companies and products. I have an intermediate table, Company_Product, that relates them.
Each company/product combination has a unique SKU. For example Acme widgets have SKU 123, but Omega widgets have SKU 456. I added the SKU as a field in the Company_Product intermediate table.
EF generated a model with a 1:* relationship between the company and Company_Product tables, and a 1:* relationship between the product and Company_Product tables. I really want a : relationship between company and product. But, most importantly, there's no way to access the SKU directly from the model.
Do I need to put the SKU in its own table and write a join, or is there a better way?
I just tested this in a new VS2010 project (EFv4) to be sure, and here's what I found:
When your associative table in the middle (Company_Product) has ONLY the 2 foreign keys to the other tables (CompanyID and ProductID), then adding all 3 tables to the designer ends up modeling the many to many relationship. It doesn't even generate a class for the Company_Product table. Each Company has a Products collection, and each Product has a Companies collection.
However, if your associative table (Company_Product) has other fields (such as SKU, it's own Primary Key, or other descriptive fields like dates, descriptions, etc), then the EF modeler will create a separate class, and it does what you've already seen.
Having the class in the middle with 1:* relationships out to Company and Product is not a bad thing, and you can still get the data you want with some easy queries.
// Get all products for Company with ID = 1
var q =
from compProd in context.Company_Product
where compProd.CompanyID == 1
select compProd.Product;
True, it's not as easy to just navigate the relationships of the model, when you already have your entity objects loaded, for instance, but that's what a data layer is for. Encapsulate the queries that get the data you want. If you really want to get rid of that middle Company_Product class, and have the many-to-many directly represented in the class model, then you'll have to strip down the Company_Product table to contain only the 2 foreign keys, and get rid of the SKU.
Actually, I shouldn't say you HAVE to do that...you might be able to do some edits in the designer and set it up this way anyway. I'll give it a try and report back.
UPDATE
Keeping the SKU in the Company_Product table (meaning my EF model had 3 classes, not 2; it created the Company_Payload class, with a 1:* to the other 2 tables), I tried to add an association directly between Company and Product. The steps I followed were:
Right click on the Company class in the designer
Add > Association
Set "End" on the left to be Company (it should be already)
Set "End" on the right to Product
Change both multiplicities to "* (Many)"
The navigation properties should be named "Products" and "Companies"
Hit OK.
Right Click on the association in the model > click "Table Mapping"
Under "Add a table or view" select "Company_Product"
Map Company -> ID (on left) to CompanyID (on right)
Map Product -> ID (on left) to ProductID (on right)
But, it doesn't work. It gives this error:
Error 3025: Problem in mapping fragments starting at line 175:Must specify mapping for all key properties (Company_Product.SKU) of table Company_Product.
So that particular association is invalid, because it uses Company_Product as the table, but doesn't map the SKU field to anything.
Also, while I was researching this, I came across this "Best Practice" tidbit from the book Entity Framework 4.0 Recipies (note that for an association table with extra fields, besides to 2 FKs, they refer to the extra fields as the "payload". In your case, SKU is the payload in Company_Product).
Best Practice
Unfortunately, a project
that starts out with several,
payload-free, many-to-many
relationships often ends up with
several, payload-rich, many-to-many
relationships. Refactoring a model,
especially late in the development
cycle, to accommodate payloads in the
many-to-many relationships can be
tedious. Not only are additional
entities introduced, but the queries
and navigation patterns through the
relationships change as well. Some
developers argue that every
many-to-many relationship should start
off with some payload, typically a
synthetic key, so the inevitable
addition of more payload has
significantly less impact on the
project.
So here's the best practice.
If you have a payload-free,
many-to-many relationship and you
think there is some chance that it may
change over time to include a payload,
start with an extra identity column in
the link table. When you import the
tables into your model, you will get
two one-to-many relationships, which
means the code you write and the model
you have will be ready for any number
of additional payload columns that
come along as the project matures. The
cost of an additional integer identity
column is usually a pretty small price
to pay to keep the model more
flexible.
(From Chapter 2. Entity Data Modeling Fundamentals, 2.4. Modeling a Many-to-Many Relationship with a Payload)
Sounds like good advice. Especially since you already have a payload (SKU).
I would just like to add the following to Samuel's answer:
If you want to directly query from one side of a many-to-many relationship (with payload) to the other, you can use the following code (using the same example):
Company c = context.Companies.First();
IQueryable<Product> products = c.Company_Products.Select(cp => cp.Product);
The products variable would then be all Product records associated with the Company c record. If you would like to include the SKU for each of the products, you could use an anonymous class like so:
var productsWithSKU = c.Company_Products.Select(cp => new {
ProductID = cp.Product.ID,
Name = cp.Product.Name,
Price = cp.Product.Price,
SKU = cp.SKU
});
foreach (var
You can encapsulate the first query in a read-only property for simplicity like so:
public partial class Company
{
public property IQueryable<Product> Products
{
get { return Company_Products.Select(cp => cp.Product); }
}
}
You can't do that with the query that includes the SKU because you can't return anonymous types. You would have to have a definite class, which would typically be done by either adding a non-mapped property to the Product class or creating another class that inherits from Product that would add an SKU property. If you use an inherited class though, you will not be able to make changes to it and have it managed by EF - it would only be useful for display purposes.
Cheers. :)