SQL Databases, Entity Data Models and 1 to 1 entities - c#

I am quite new to EDMs, having written quite a lot of ADO.Net stuff in the past. I have three tables:
**Product:**
Prod_ID - PK
**Product_MaxLoan**
Prod_ID - PK
**Product_MinLoan**
Prod_ID - PK
These tables, hosted in MS SQL 2005, have no FKs or constraints configured as yet, they are to have a notional 1 to 1 relationship. For example, every row of a Product with ID of 1, there will be a row in Product_MaxLoan and Product_MinLoan each with an ID of 1.
In Visual Studio 2010, I want to set the EDM up correctly so that the cardinality is set to 1 to 1. I previously had FK constraints on the tables and the following set up, however, this would only allow a 0..1 cardinality (to cater, I suppose, for the fact a Product may not have a Product_MaxLoan or Product_MinLoan).
**Product:**
Prod_ID - PK
**Product_MaxLoan**
ID - PK
Prod_ID - FK
**Product_MinLoan**
ID - PK
Prod_ID - FK
Questions:
What advice would you give for setting these tables up in SQL 2005? For a 1 to 1 relationship in an EDM would you set up FKs?
Can you set up a PK relationship in SQL 2005 that the EDM will read when importing from a database?
A product contains some 300 properties, so containing all of this
data in a single table would be poor database normalization (hence
the many 1 - 1 tables). Would best practice be to put all of these
properties into a single EDM class? My gut reaction is to break it
down much as it is structured in the DB (this is my ADO heritage
coming to the fore), having a class for each logical part of the
product.
Your advice would be appreciated.
Best regards,
Mark

In database use this configuration:
**Product:**
Prod_ID - PK
**Product_MaxLoan**
Prod_ID - PK, FK (to Product)
**Product_MinLoan**
Prod_ID - PK, FK (to Product)
This will force one-to-one relation on database level as well as in EF. The relation itself will be 1 - 0..1 (Product can exists without MaxLoan and MinLoan) because real 1 : 1 cannot exist in database. Real 1 : 1 demands that both entities always exists = you cannot insert the first if the second doesn't exist and you cannot insert the second if the first doesn't exists. How do you insert them without turning off referential integrity?

Related

Having an entity possess multiple one to one relationships? Entity Framework

Does having a child with multiple one to one parents in a parent table make sense? Or would there be a more advantageous way to configure the relationship?
Ef core details:
Say I have a ProductSales table already, and I'd like to have a separate table that has a one to one with 2 ProductSales (for aggregating and comparing 2 product sales).
ProductSales
StoreId PK
ProductId PK
Date PK
SalesAmount
DailyChange
StoreId PK, FK1
ProductId PK, FK2
First Date FK1
Second Date FK2
AmmountDifference
Each ProductSales row will only be referenced once in the DailyChange table.
Does it make sense to have 2 one to one relationships between these 2 tables?
DailyChange --------- ProductSales1
DailyChange --------- ProductSales2
Daily Change builder:
builder.HasOne(b=> b.InitialProductSales)
.WithOne()
.HasForeignKey<DailyChange>(b => new { b.StoreId, b.ProductId, b.Date});
(and a similar one for the end date)

c# Entity Framework using rowbegindate in transaction table

I'm a developer that started working with a database architect. He is using a design I've never seen before, that I think will have negative performance implications.
In transaction tables he is using two fields in every table.. rowbegindate and rowenddate. There is a parent table that just a few fields that never changes. This is called a PersonHeader table. That key is used a fk to the child Person table. The Person table's PK is the fk of the PersonHeader table AND the RowBeginDate for that row. To retrieve the current row, I need to always check the for the RowEndDate that is NULL.
I haven't gotten into the details yet of how this will affect performance of Entity Framework, but I suspect that it will not be efficient.
I've worked on a number of projects and have never seen this approach. What are the performance implications of having this many dead records in a transaction table. I don't think there will be many updates, but I would estimate that the database person table could end up having 500,000 rows or more, not to mention the detail tables.
When working with applications that have auditing requirements, it is not uncommon to have to maintain historical versions of records. I have done similar things using (for example, when storing a history of changes to employee records), an EmployeeID and UpdatedOn field as a key so I can get the latest version of the record.
Provided that the tables are properly indexed and that the indexes don't end up being too large because of the composite key, I wouldn't worry about performance or the number of records. I've worked with tables that contained half a billion records and performance was still fine (rebuilding the indexes took a while though).
You could even create an interceptor from entity framework that would allow you to filter out "dead" records when performing your queries (see Entity Framework soft delete implementation using database interceptor not working)
PersonHeader
PersonKey (PK)
Person
PersonKey (PK, FK)
RowBeginDate(PK)
RowEndDate
(other columns)
(I added this as an answer, since a comment wouldn't take a new line...)
PersonLocation
LocationTypeKey (PK, FK)
PersonKey (PK, FK)
LocationKey (FK)
RowBeginDate (not a key)
RowEndDate
Location
LocationKey (PK)
StateKey (FK)
RowBeginDate (not a key)
RowEndDate

Entity Framework maps data wrong when the identity column is not unique

Without getting into the "why", just understand this in inherited and what I have to work with :)
I have an EF6 edmx mapped to a view. There is no identifying column on it, so in order for EF to map the entity, the first not-null column was selected as the PK. The original thought behind this was it is read only no updates or deletes would be done. There is no filtering (ODATA sits on top of this), and the only - and I mean only - way this is used is select top N * from the entity.
There are 4 records in the view.
TypeCode | Contact | UserID | LocaleID | EntityName
---------------------------------------------------------
1 6623 1032 9 Jane
1 6623 1032 9 Jane
1 6623 1032 9 John
1 6623 1032 9 John
The problem I am seeing is that EF is mapping all 4 rows the same. All "John" names above become "Jane"
OK, putting aside the design decision, and the fact there is no identifying record on the view, why is EF mapping the last two rows wrong? My initial thought is that since the "PK" is set as TypeCode It doesn't know how to do it. But why would it be using the key column when just reading results from the database? I would have thought it only mattered for updates and deletes
If you query data by Entity Framework, the default behavior is that each materialized entity is tracked by its unique key. The unique key consists of any properties you told EF to use as key, or, alternatively, it inferred as key properties (TypeCode in your case). Whenever a duplicate entity key tries to enter the change tracker, an error is thrown telling that the object is already being tracked.
So EF simply can't materialize objects having duplicate primary key values. It would compromise its tracking mechanism.
It appears that, at least in EF6, AsNoTracking() can be used as a work-around. AsNoTracking tells EF to just materialize objects without tracking them, so it doesn't generate entity keys.
What I don't understand is why EF doesn't throw an exception whenever it reads duplicate primary key values. Now it silently returns the same object as many times as it encounters its key value in the SQL query result. This has caused many many people to get confused to no end.
By the way, a common way to avoid this issue is by generating temporary unique key values to the view by using ROW_NUMBER in Sql Server. That's good enough for read-only data that you read once into one context instance.

SqlBulkCopy for two tables with one-to-many association

I have used SqlBulkCopy in my previous program and have enjoyed the speed-of-light advantage of its INSERTS. But then, I was only inserting things in one table only.
I now have two tables with a one-to-many association i.e. table A has a foreign key in table B. So each record in B carries an id that is the result of an insert in A.
I am wondering if there is a solution for this?
Example:
I will give a better example on this and hope we find a good solution eventually.
We have a table called Contacts. And since each contact can have zero or more Email addresses we will store those emails in a separate table called ContactEmails. So Contacts.Id will become FK on ContactEmails (say ContactEmails.ContactId).
Let's say we would like to insert 1000 Contacts and each will have zero or more Emails. And we of course want to use SqlBulkCopy for both tables.
The problem is, it is only when we insert a new Contact that we know his/her Id. Once the Contact is inserted, we know the inserted Id is e.g. 15. So we insert 3 emails for this contact and all three will have ContactEmails.ContactId value of 15. But we have no knowledge of 15 before the contact is inserted into the database.
We can insert all contacts as bulk into the table. But when it comes to their email, the connection is lost because emails do not know their own contacts.
Disable the constraints (foreign key) before bulk insert. Then enable it again.
Make sure you do not have referential integrity violations.
You can disable FK and CHECK constraints using below query:
ALTER TABLE foo NOCHECK CONSTRAINT ALL
or
ALTER TABLE foo NOCHECK CONSTRAINT CK_foo_column
Primary keys and unique constraints can not be disabled, but this should be OK if I've understood you correctly.

De-normalize table or use Joins in Entity Framework

I need to know what are the tradeoffs of using a denormalized table vs using two separate tables and accessing the data using joins. I am using Entity Framework 4.
In my case I have two tables Order and OrderCategoryDetails.
I am thinking whether merging these two tables into one single table is better?
If denormalized, the added columns (OrderCategory and OrderSubcategory will be will be sparse (could be 100% empty. Will always be at least 50% empty)
On the other hand, if I keep it as it is, I am worried about frequent join operations being executed (i.e. whenever I am querying for a specific Order, I would need information from OrderCategoryDetails too.
At present, I have normalized tables and use navigational properties:
To access Order Category information from OrderItem instance
OrderItem orderItem = _context.OrderItems.Where(...).FirstOrDefault();
if(2 == orderItem.SalesOrder.Category.OrderCategory){ ...}
To access Order Category information from Order instance
Order order = _context.Orders.Where(...).FirstOrDefault();
if(2 == order.Category.OrderCategory){ ...}
This is my schema:
Table : Order
ID (Primary Key)
Date
Amount
ItemCount
OrderCategoryInfo (FK - join with OrderCategoryDetails on OrderCategoryDetails.ID)
Table : OrderCategoryDetails
ID (Primary Key)
OrderCategory
OrderSubCategory
Table : OrderItem
OrderItem ID (Primary key)
Order ID (FK - Join with Order)
Database used: SQL Server 2008 R2
My general advice would be to ask yourself the following question; does every single row from the first table require a row from the second table? If the answer is yes then you might be better off de-normalising the data. If the answer is no you're probably better off keeping it as a seperate table.
As long as you set up your foreign key association between the two tables you shouldn't concern yourself with performance implications of performing a join. It will only become an issue in pathological situations.
Based upon your answers in the comments thread, I'd recommend that you should keep the tables separate and set up a foreign key relationship between the two.
If you do get any performance problems further down the line, run a profiler on the problematic SQL and add any indexes that the profiler recommends, but only do this for queries that are used frequently. Indexes are great for speeding up queries but come at the cost of insert performance, so take care with them.

Categories

Resources