Entity Framework model and foreign key property - c#

I have 2 tables that I import to EF model.
First table has a property [section] that acts as foreign key to the second table.
When I map this property in model to the table and try to compile I get this error:
Problem in Mapping Fragments starting
at lines 158, 174: Non-Primary-Key
column(s) [Section] are being mapped
in both fragments to different
conceptual side properties - data
inconsistency is possible because the
corresponding conceptual side
properties can be independently
modified.
If i remove this property from the model it passes, but when I query the data I don't have the section field.
I know that I can get it by using the navigation field and reading this property from the second table, but to make it work I must include the other table in my query.
var res = from name in Context.Table1.Include("Table2")...
Why do I need to include the association just for one field?
UPDATE
To make it more clear:
Table 1 has fields:
ItemId - key
section - foreign key
title
Table 2 has fields:
SectionId - key
Name
When I set the associations the section property from the first table must be removed.

What are your Primary Keys and is one Store Generated? I suspect you are missing a PK or an Identity somewhere.
Tip: One alternative when having mapping problems is to create the model you want in the EDMX designer and then ask it to create the database for you. Compare what it creates to what you have made in SQL and it's often easy to spot the mistakes.

In EF 4 you can use FK associations for this.
In EF 1 the easiest way to get one field from a related table is to project:
var q = from t1 in Context.Table1
where //...
select new
{
T1 = t1,
Section = t1.Section.SectionId
};
var section = q.First().Section;
If it's a key property, you can get the value via the EntityKey:
var t1 = GetT1();
var section = (int)t1.SectionReference.EntityKey.Values[0].Value;
Generally, I don't like this last method. It's too EF-specific, and fails if your query MergeOption is set to NoTracking.

Related

Navigation properties when datatypes does not match in Entity Framework

I am trying to map a legacy database into an Entity Framework Model. The database is very generic, and most data are stored in the tables "Object" and "Event". The columns are named things like "Date1", "Num11", "Text4". There are no explicit foreign keys defined in the database.
Here is a subset of the two tables:
CREATE TABLE [Object] (
[ObjectId] int not null identity(1,1) primary key,
[ObjectTypeId] int,
[Name] varchar(100)
);
CREATE TABLE [Event] (
[EventId] int not null identity(1,1) primary key,
[EventTypeId] int,
[Subject] text,
[Body] text,
[Date1] datetime,
[Num11] decimal(18,2)
);
For some values of EventTypeID, the Num11 field references an Object. I can easily write a join between the tables:
SELECT
ev.[EventId], ev.[Subject], ev.[Body], ev.[Date1] AS [CreatedDate],
p.[ObjectId] AS [PersonId], p.[Name] AS [PersonName]
FROM [Event] ev
LEFT JOIN [Object] p ON p.ObjectId = ev.Num11
WHERE ev.[EventTypeId] = 7
AND ev.[Date1] > '2013-04-07'
In the Entity Framework designer, I can create a separate Entities for each type of object, and rename the columns appropriately. The problems start when I try to create navigation-properties between the Entities, since the foreign key column type does not always match the primary key.
Neither SQL Server, nor Entity Framework, will allow me to create a foreign key reference between the columns.
How can I create navigation-properties between entities, when the FK an and PK datatypes does not match exactly? Something that enables me to include the related entity in a LINQ query, and hopefully be able to expose it in a OData service.
I can't make any changes to existing tables in the database, but if required, I could add views. Though I would need to be able to save the entities back to the database.
Not a pleasant design, but there are some options left. This is what you can do:
Create a 1:1 view on Event with an additional column that converts the decimal to an integer. The property should be marked as computed.
Use the property in a FK association with Object, so Object has a navigation property EventViewItems (if you like) that maps to the view. (You must add the association manually in the edmx designer and tweak the foreign key field).
Read the objects and events in one linq statement like db.Objects.Include(o => o.EventViewItems)
But you can't
Add events to db.Objects.EventViewItems, because you can't write into the FK field.
Add events to db.EventViewItems because there is no InsertFunction defined for a view. (Unless you hack the view into the model as a table).
So you'll have to include the original Event in the model too and use that to create/update/delete (CUD) individual Event objects.
Feels a but shaky, because you have to watch your steps not to run into runtime exceptions. On the other hand you'll have separate paths for reads and CUD. Call it CQRS and this design suddenly is cutting edge.
You can try this. Change the type of Num11 in the model to integer. In the efconfiguration of Event set the databasetyp of num11 to int with xx.HasColumnType("int").

C# Entity Framework: Update Query Does not work

I have this simple code : (update value)
I'm trying to update column "c"
using (MaxEntities ctx = new MaxEntities())
{
aa orders = (from order in ctx.aa
select order).First();
orders.c = 22;
ctx.SaveChanges();
}
this is the table :
CREATE TABLE [dbo].[aa](
[a] [int] NULL,
[b] [int] NOT NULL,
[c] [int] NOT NULL
) ON [PRIMARY]
and values inside :
but i get an exception :
The property 'c' is part of the object's key information and cannot be modified.
I'm new to EF.
any help will be much appreciated.
The property 'c' is part of the object's key information and cannot be modified.
That's why you can't edit it. Maybe you need to add id column as a key with identity specified
As explained in another answer EF must uniquely identify every entity. If you don't have PK in the database, EF will infer some key. Key is considered as fixed so if EF inferred c as part of the key (and it did it because it uses all non-nullable non-binary columns) you cannot change its value. Moreover EF takes all tables without primary key as readonly so even if you remove c from the key in the designer and modify c value you will get another exception when you execute SaveChanges.
The reason for the second exception is in the way how EF describes model and the database. When EF inferred key, it did it only for description of your entities and for context's internal needs but not for description of the database. When EF tries to save changes it builds UPDATE statement from database description and without information about real database PK columns it will not be able to identify correct record for update (every update in EF can affect only single record - EF checks ROWCOUNT). This can be solved by cheating EF and updating its database description = by describing some column in the table description as primary key. This leads to multiple problems:
You must have some unique column in the database otherwise this method will not work.
You must edit EDMX manually (as XML) to add this change
You must not use default MS EDMX designer for updating your model from database because it will delete your change
Simple advice: Either use database tables with primary keys or don't use Entity framework.
Primary key missing here. Add primary key in table and it work.
I believe if there's no PK at all, EF uses all of the fields/columns as part of the key info.Here's a nice explanation: by #SteveWilkes of why. But what do your entities look like? The other possibility is that it doesn't have a property because the association is inside a different entity, if this is a foreign key.
EDIT
This got me thinking. There are just going to be situations where you have to work with legacy tables having no PK, even if you would never create such a thing. What about views? EF is a mapper - it has to uniquely identify that record so it infers and defines this key. Yes, you could use stored procedures, but could you also hack the XML and remove the keys from the table definition?
AND EDIT AGAIN
After posting this, I see #Ladislav Mrnka already said a similar idea (cheating EF and updating its database description), so it has been done (WARNING: Consume at your own risk - never tried). Quick google got me this blog with clear instructions:
Close the model designer in Visual Studio if it is still open and re-open the .edmx file in an XML editor
Find the edmx:StorageModels -> Schema -> Entity Container -> EntitySet element that refers to the table in question
On the EntitySet element, rename the store:Schema attribute to Schema
Remove the store:Name attribute altogether
Remove the opening and closing DefiningQuery tags and everything in between them
Save and close the .edmx file
But really, who doesn't like a PK? Can you not add an id?

Inserting relational data with Linq to SQL results in duplicate entry error

I have drawn up a database design in the Visual Studio database diagram editor, and created all of my tables from that. I also created a Linq to SQL class and added my tables to create objects for each table. I am running into an issue when trying to insert new entries to the database.
For example:
Let's say I have two tables, Artists and Albums. A single Artist can have multiple Albums (one-to-many). Album has an ArtistID field which is a FK to the ArtistID PK in the Artist table. Their IDs are GUIDs which are auto generated by the database.
Now in my code I create a new Album object (called myAlbum) and set its Artist object to an Artist that is already in the database (myArtist).
If I do something like this:
DatabaseDataContext context = new DatabaseDataContext();
context.Albums.InsertOnSubmit(myAlbum);
context.SubmitChanges();
I end up getting a SqlException saying: "Violation of PRIMARY KEY constraint 'PK_Artist'. Cannot insert duplicate key in object 'dbo.Artist'.
The statement has been terminated."
If I compare myAlbum.Artist to the Artist already in the database, Linq says they are equal, so it knows they are the same object.
How do I get Linq to insert the new Album object and link it to the existing Artist in the database already, without trying to insert the Artist again?
Apparently, you set the Album's Artist property with an object that was fetched with an other datacontext instance. Therefore, your new DatabaseDataContext "thinks" the Artist must be inserted.
You can either set Album.ArtistId (not the Artist object), or fetch the Artist in the same data context and add the album to its Albums collection.
By the way, using (var context = new DatabaseDataContext()) { ... } is better.
You need to solve the duplicate primary key first and with my test I created my primary table with a primary key of UNIQUEIDENTIFIER and with a default value of (newid()).
Then when you drag your table into your Linq To SQL class project, the table class is created with everything you wanted except: The Primary Key Column should have its Auto Generate Values set to true but its not! By default is false when your column data type is of type UNIQUEIDENTIFIER.
Then I dropped the column in MS SQL and recreated it with a data type of INT dragged it into the Linq to SQL class and it then set the column property Auto Generate Values to true.
So if you use the UNIQUEIDENTIFIER you need to manually set the Auto Generate Values property to true.
I think that the duplicate primary key may be GUID.Empty. If my understanding is correct.
I would think solutions for this problem.
set default value of the pk_artist column to be newid(). That allow the primary Kerr auto generated.
Or
Explicit assign primary key to entity.
myAlbum.Pk_Artist = GUID.NewGiud();
context.Albums.InsertOnSubmit(myAlbum);
Hope this help

EntitySet<T> in LINQ to SQL- using it and removing it

I've got a pair of tables in my database. One of which has a primary key (a simple numerical ID), the other has that ID as a foreign key.
The first table has suddenly gained an EntitySet<OtherTable>. If I add a new OtherTable() to this, is it automatically sent to the database, and the ID's linked up, etc, when I use SubmitChanges()?
Secondly, the relationship isn't many-to-one, it's one-to-one, a corresponding entry in the second table is optional and singular. As such, a container like EntitySet isn't really appropriate for this relationship. An OtherTable? would be a more appropriate representation. How can I inform LINQ to SQL of this?
Set Unique = true in the associaton properties. That should adjust it to being 1:1

Table-per-type inheritance insert problem

I followed this article on making a table-per-type inheritance model for my entities, but I ran into some issues. Below I'm posting steps to reproduce the problem I'm having in a minimal environment to rule out other factors.
First, I created a new MS SQL Server 2008 R2 database with the following two tables:
Users
Id : bigint (PK and set it as the identity column)
Name : nvarchar(25) NOT NULL (whatever, some random property
Customers
Id : bigint (PK, identity column, and FK on Users.Id)
Title : nvarchar(25) NOT NULL (also whatever, some random property)
Next, I generated the .edmx entity model from the database, and followed the link at the top verbatim. That is to say, I deleted the association between User and Customer, set User as the base class of Customer, deleted the Id property from the Customer entity, and made sure that the Customer.Id column was mapped to the inherited User.Id property. I then ran the following small program:
using (var db = new EF_Test.testEntities())
{
var cust = db.Users.CreateObject<Customer>();
db.Users.AddObject(cust);
db.SaveChanges();
}
I get the following error when I make that last call:
"A value shared across entities or associations is generated in more than one location. Check that mapping does not split an EntityKey to multiple store-generated columns."
With the following inner exception:
"An item with the same key has already been added."
Any ideas on what I could be missing?
A quick google on the error message turned up the following solution, maybe it helps you:
http://social.msdn.microsoft.com/Forums/en/adodotnetentityframework/thread/4bfee3fd-4124-4c1d-811d-1a5419f495d4
I think that I figured it out. The
table for the Party sub type had its
key column set to autogenerate a key
value and since it's derived, the EF
wanted to set that value explicitly.
So have you tried removing the "identity" setting from the customer table? So it doesn't autogenerate the primary key?
Hope this helps.
I finally found the source of my troubles. For those still interested, in the Customers table, the Id column should not have been set to the identity column of the table (PK and the FK dependency are fine though).
Why you don't want to make a foreign key (UserId) as a separate column? Maybe it can help you.
Also try to use model first approach and generate db after model creation as it is described in the following article.

Categories