Entity Framework many to many relationship with extra field (Database First) - c#

I have a program using Entity Framework (EF) Database First in the data access layer. I know that in order for EF to auto-generate the navigation properties of a many to many relationship, the mapping table needs to contain only a composite primary key:
Project
- ProjectId (PK)
- Name
ContentType
- ContentTypeId (PK)
- Name
ProjectContentTypeMapping
- ProjectId (PK)
- ContentTypeId (PK)
In this case everything works fine, and I can access Projects from ContentTypes and the other way around with navigation properties.
However I have a requirement to have extra fields that are particular to the relation between Projects and ContentTypes, and that would be extra columns in the ProjectContentTypeMapping table. Once I add these I loose the navigation properties, and EF shows the mapping table in the designer.
Is there any way I can manually configure the mapping between these two tables in EF (Database First)? Alternatively, how can I represent this? I was thinking of maybe having an extra "metadata" table with a FK to the mapping table, but it looks "hacky" to me...
Thanks

No, you cannot have extra columns in your mapping table in entity framework.
Because, having an extra column implies you intend to use it, but Mapping tables are not part of the entity, so, entity framework, no longer treats your mapping table with extra columns as a Mapping table. You will have to manipulate the Mappings manually.
Lets take example of your classes:
Project
- ProjectId (PK)
- Name
- ProjectContents
ContentType
- ContentTypeId (PK)
- Name
- ProjectContents
ProjectContentTypeMapping
- ProjectId (PK)
- ContentTypeId (PK)
- OtherRelevantColumn
where ProjectContents is of type ProjectContentTypeMapping
so whenever you add a Project with Certain ContentType, you would be doing this:
Project prj = new Project();
//fill out scalar properties
ProjectContentTypeMapping pctm = new ProjectContentTypeMapping();
pctm.ContentTypeId = 1; //or whatever you want, or selected from UI
prj.ProjectContents = new ProjectContentTypeMapping();
prj.ProjectContents.Add(pctm);
dataContext.Projects.Add(prj);
Now in case of editing (adding ContentTypes) to an existing project, you won't do prj.ProjectContents = new ... rather, you would do it only when it is null i,e,
if(prj.ProjectContents==null)
prj.ProjectContents = new ProjectContentTypeMapping();
also, one very very important thing, since now your ProjectContentTypeMapping is no longer a mapping table, so, deleting a Project would give you an error, if its id is being present in ProjectContentTypeMapping table; you will have to remove them manually i.e
foreach(var pctm in prj.ProjectContents.ToList())
{
prj.ProjectContents.Remove(pctm);
datacontext.ProjectContentTypeMappings.Remove(pctm);
}
datacontext.Remove(prj);
datacontext.SaveChanges();

Related

Create Association Model First With Ignoring Certain PKs

I have the following Table Structure
Facility
PK Facility ID
AccountID
Accounts
PK NameID
PK AccountID
I can't touch the DB so my changes need to be in Entity Framework. Essentially the AccountIDs are linked so I want to create an association between them. So when I create an association I map the AccountIDs together, however I can't map FacilityID to anything and NameID to anything so when I save Visual Studio complains that the mapping is not set correctly.
My main question is how do I ignore the mappings for FacilityID and NameID? I've tried added [NotMapped] to both FacilityID and NameID but that does not work. I've also tried creating a scalar property for Facility and Accounts and used the Referntial Constraint to map them however when I try to map the columns under Table Mapping, the columns I added do not show up which causes VS to complain as well.
Here is my table, I removed most of the fields because they are unnecessary
Assuming Account.AccountID is unique (ie no two rows in Account actually have the same AccountID), just declare that as the only Key Property on the Account entity.
The Key of an entity does not have to be declared as the PK in the database. But you can only have one Key per entity (the Key can, of course, have multiple columns, and EF Core does support alternate keys). The entity Key should be unique, and should have a unique index in the database on the corresponding columns, but that's not enforced by EF.

Disable associations when a foreign key do not exist

I've created an edmx for my database. In it Entity framework removed a table and instead created an association between two tables because it matches a column name with the primary key in the other table.
I do not want that as there is no real association between those tables. How can I remove that association and get a class for the middle table instead?
Example:
SomeTable
Id int pk
MiddleTable
SomeTableId int fk
SomeCode int
OtherTable
SomeCode int pk
It's the MiddleTable which do not get a class.
Remove one table from the edmx, e.g. OtherTable.
Update model from database and add MiddleTable.
Update model from database and add OtherTable.
When I do this with a similar model I end up with an association between SomeTable and MiddleTable and an unassociated OtherTable. Now you can add/remove associations manually as you wish.
It's normal EF behavior not to create a class for the middle table. This is a so-called many to many association between SomeTable and OtherTable which can be modelled by two collection properties:
SomeTable.OtherTables
OtherTable.SomeTables
The middle table, the junction table, is not really necessary.
It's a bit surprising to me that you say that there is no association between the two tables although, apparently, in the database there are foreign keys. Technically, it is a many to many association.

EF4: Using the same table twice

I'm using an Oracle datasource, reading data only, not writing, I can not alter anything on the database.
Imagine this scenario of 2 tables, a Courses Table and a Memos Table.
The Courses table has 2 links to the memo (MemoId) table.
So...
Course table
CourseId
Title
SummaryNarrationMemoId
PreCourseInformationMemo
MemoToString table
MemoId
MemoData (Binary)
So the course table joins to the Memo Table twice, for different reasons.
I looked down the EF Inheritance route for using the same table twice, using the Memo table as the base, and creating PreCourseMemo and SummaryNarrationMemo, but that throws these errors on build:
I updated the model to add the two tables to the model.
Error 3005: Problem in mapping fragments starting at line 613:Must specify mapping for all types in Set MemoToStringTables.
An Entity with Key (PK) will not round-trip when:
Entity is type [MyModel.MemoToStringTable]
Error 3005: Problem in mapping fragments starting at line 613:Must specify mapping for all types in Set MemoToStringTables.
An Entity with Key (PK) will not round-trip when:
Entity is type [MyModel.PreCourseMemo]
Error 3005: Problem in mapping fragments starting at line 613:Must specify mapping for all types in Set MemoToStringTables.
An Entity with Key (PK) will not round-trip when:
Entity is type [MyModel.SummaryNarrationMemo]
I know I could create a view for each on the database, but it doesn't feel right. :( Any thoughts?
If I understand your problem correctly, it will not work. You are trying to map inheritance to the Memo table but to do that you Memo table must contain special discriminator column which will tell EF if it is PreCourseMemo or SummaryNarrationMemo. You cannot differ those types just by relation to course.

Defining a 1 to many relationship in Entity Framework

I'm trying to create a 1:m relationship using Entity Framework (.net 4.0) and am getting the following error:
App_Code.Model.msl(36,6) : error 3007: Problem in mapping fragments
starting at lines 6, 36:Column(s) [ProductId] are being mapped in
both fragments to different conceptual side properties.
What i have is a Products table, and a Features table. The idea is that Products have many Features. Products each have a ProductId, and the Features have a ProductId foreign key.
Now the catch is that the foreign key doesn't exist in sql server, and i don't want it to. If it did, then it all automagically works nicely.
In the EDMX designer, i created an association from the product to the feature entity, then edited the mapping details of the ProductFeature association to be based on the Features table, which i think would make it work.
Any ideas? Thanks very much.
This is a M x N relationship. Why? Because a feature can be assigned to more than one type of product.
You should have a table ProductFeatures like so:
ProductId FeatureId
1 1
1 2
2 1
2 2
Found one solution: delete the scalar property 'ProductId' from the feature entity:
http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/a71901fb-97ec-4072-949a-c0c66a9775b1
However, in the auto-generated relationships that EF gives you if you set up the foreign key in the database, the eg 'ParentId' fields are present in the child as a scalar field.
So i'm a little confused still.
-edit- Further help:
http://www.hanselman.com/blog/CreatingAnODataAPIForStackOverflowIncludingXMLAndJSONIn30Minutes.aspx

Entity Framework model and foreign key property

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.

Categories