I'm trying to create a script to generate tests from an entity framework edmx file. I want to ensure columns are all written and relationships are correct.
I can't compare columns that are database keys since these are automatically generated. The database model also includes references from child records to parents. Any suggestions how to detect columns in the child tables that reference parents? (Columns that participate in relationships).
I've figured out how to iterate over the columns, and to exclude the key column for each table:
var sqlColumns = typeMapper.GetSimpleProperties(entity);
if (sqlColumns.Any())
{
foreach (var sqlColumn in sqlColumns)
{
if ( ! ef.IsKey(sqlColumn) )
{
#>
// test for non relationship columns goes here
<#
}
}
}
This version of EF includes the file:
<## include file="EF.Utility.CS.ttinclude"#><##
Related
I have a database with three tables: Word, Idiom, WordIdiom that stores many to many relation between this two tables. WordItem includes only foreign keys for Word and Idiom tables.
After that, I have created Entity model, based on database. I have filled two tables with relevant content, and now I want to add cross-links between these tables.
So, I have written this code:
using (var db = new IdiomsDictionaryEntities())
{
var allIdioms = from idiom in db.Idioms select idiom;
foreach (var idiom in allIdioms)
{
string[] words = idiom.IdiomText.Split(new[] { " ", "-" }, StringSplitOptions.None);
foreach (var word in words)
{
var wordItem = db.Words.SingleOrDefault(exWord => exWord.WordString.ToLower().Equals(word));
if (wordItem == null)
{
Console.WriteLine("Idiom: " + idiom.IdiomText + ", missing word: " + word);
continue;
}
idiom.Words.Add(wordItem);
db.SaveChanges();
}
}
}
But when I run this code, I'm getting following error:
An unhandled exception of type 'System.Data.Entity.Infrastructure.DbUpdateException' occurred in EntityFramework.dll
Additional information: An error occurred while saving entities that do not expose foreign key properties for their relationships. The EntityEntries property will return null because a single entity cannot be identified as the source of the exception. Handling of exceptions while saving can be made easier by exposing foreign key properties in your entity types. See the InnerException for details.
Inner-inner exception:
Unable to update the EntitySet 'WordIdiomMatch' because it has a DefiningQuery and no element exists in the element to support the current operation.`
As it is my first time with Entity Framework, I'm really don't know how to fix this. I have tried to add [ForeignKey()] property to Entity Framework models, but probably have done it wrong. I have also tried to add a primary key for WordIdiom, but it brakes even more things, as in this case I cannot even add items to Word and Idiom tables.
I have solved the problems, with help of #KerryRandolph and #AntoinePelletier
I was trying to update entities derived from a many-to-many relationship using Pure Join Table - meaning no other columns except foreign keys are allowed.
If you add a Primary Key column to a Join Table, you lose all of the entity framework advantages and have to implement insertion operation manually.
Proper solution was to alter the join table on the DB to make a PK that includes BOTH of the foreign ID columns.
First of all, i see that you have 2 add() for the same purpose. Witch is wrong. Imagine what it would look like in the data base :
wordItem.Idioms.Add(idiom);
ok now X and Y are linked by the link table as "X-Y" record.
idiom.Words.Add(wordItem);
And now... it would create another record that link these as "Y-X" witch is useles, if there is already an "X-Y" record then X is linked to Y with this single record and the other way around too.
And i'd say... usualy the primary key of a link table is the combination of the two foreign keys it contain, so the double add would crash anyway.
I am using EF 6 Code-First, table per type, and I have two concrete classes Group and User. Group has a navigation property Members which contains a collection of User. I have mapped this many-to-many relationship in EF using Fluent syntax:
modelBuilder.Entity<Group>
.HasMany<User>(g => g.Members)
.WithMany(u => u.Groups);
I would like to be able to say when a member has joined a group so that I can query for, say, the newest member(s). I am not sure of how this is best accomplished within the framework.
I see the following options:
Create and use an audit table (ie GroupMembershipAudit consisting of Group, User, join/unjoin, and DateTime
Add a column to the autogenerated many-to-many table between User and Group
Is there anything within EF to facilitate this sort of storage of many-to-many historical info like this / append columns to the many-to-many relationship?
Add a column to the autogenerated many-to-many table between User and
Group
That is not possible - auto-generated junction tables can contain only keys (that is called Pure Join Table). According to Working with Many-to-Many Data Relationships article: If the join table contains fields that are not keys, the table is not a PJT and therefore Entity Framework cannot create a direct-navigation (many-to-many) association between the tables. (Join tables with non-key fields are also known as join tables with payload.)
Create and use an audit table (ie GroupMembershipAudit consisting of
Group, User, join/unjoin, and DateTime
Actually you should create GroupMembershipAudit entity. With Code First table will be generated, you don't need to create it manually.
We have a customer very large table with over 500 columns (i know someone does that!)
Many of these columns are in fact foreign keys to other tables.
We also have the requirement to eager load some of the related tables.
Is there any way in Linq to SQL or Dynamic Linq to specify what columns to be retrieved from the database?
I am looking for a linq statement that actually HAS this effect on the generated SQL Statement:
SELECT Id, Name FROM Book
When we run the reguar query generated by EF, SQL Server throws an error that you have reached the maximum number of columns that can be selected within a query!!!
Any help is much appreciated!
Yes exactly this is the case, the table has 500 columns and is self referencing our tool automatically eager loads the first level relations and this hits the SQL limit on number of columns that can be queried.
I was hoping that I can set to only load limited columns of the related Entities such as Id and Name (which is used in the UI to view the record to user)
I guess the other option is to control what FK columns should be eager loaded. However this still remains problem for tables that has a binary or ntext column which you may not want to load all the times.
Is there a way to hook multiple models (Entities) to the same table in Code First? We tried doing this I think the effort failed miserably.
Yes you can return only subset of columns by using projection:
var result = from x in context.LargeTable
select new { x.Id, x.Name };
The problem: projection and eager loading doesn't work together. Once you start using projections or custom joins you are changing shape of the query and you cannot use Include (EF will ignore it). The only way in such scenario is to manually include relations in the projected result set:
var result = from x in context.LargeTable
select new {
Id = x.Id,
Name = x.Name,
// You can filter or project relations as well
RelatedEnitites = x.SomeRelation.Where(...)
};
You can also project to specific type BUT that specific type must not be mapped (so you cannot for example project to LargeTable entity from my sample). Projection to the mapped entity can be done only on materialized data in Linq-to-objects.
Edit:
There is probably some misunderstanding how EF works. EF works on top of entities - entity is what you have mapped. If you map 500 columns to the entity, EF simply use that entity as you defined it. It means that querying loads entity and persisting saves entity.
Why it works this way? Entity is considered as atomic data structure and its data can be loaded and tracked only once - that is a key feature for ability to correctly persist changes back to the database. It doesn't mean that you should not load only subset of columns if you need it but you should understand that loading subset of columns doesn't define your original entity - it is considered as arbitrary view on data in your entity. This view is not tracked and cannot be persisted back to database without some additional effort (simply because EF doesn't hold any information about the origin of the projection).
EF also place some additional constraints on the ability to map the entity
Each table can be normally mapped only once. Why? Again because mapping table multiple times to different entities can break ability to correctly persist those entities - for example if any non-key column is mapped twice and you load instance of both entities mapped to the same record, which of mapped values will you use during saving changes?
There are two exceptions which allow you mapping table multiple times
Table per hierarchy inheritance - this is a mapping where table can contains records from multiple entity types defined in inheritance hierarchy. Columns mapped to the base entity in the hierarchy must be shared by all entities. Every derived entity type can have its own columns mapped to its specific properties (other entity types have these columns always empty). It is not possible to share column for derived properties among multiple entities. There must also be one additional column called discriminator telling EF which entity type is stored in the record - this columns cannot be mapped as property because it is already mapped as type discriminator.
Table splitting - this is direct solution for the single table mapping limitation. It allows you to split table into multiple entities with some constraints:
There must be one-to-one relation between entities. You have one central entity used to load the core data and all other entities are accessible through navigation properties from this entity. Eager loading, lazy loading and explicit loading works normally.
The relation is real 1-1 so both parts or relation must always exists.
Entities must not share any property except the key - this constraint will solve the initial problem because each modifiable property is mapped only once
Every entity from the split table must have a mapped key property
Insertion requires whole object graph to be populated because other entities can contain mapped required columns
Linq-to-Sql also contains ability to mark a column as lazy loaded but this feature is currently not available in EF - you can vote for that feature.
It leads to your options for optimization
Use projections to get read-only "view" for entity
You can do that in Linq query as I showed in the previous part of this answer
You can create database view and map it as a new "entity"
In EDMX you can also use Defining query or Query view to encapsulate either SQL or ESQL projection in your mapping
Use table splitting
EDMX allows you splitting table to many entities without any problem
Code first allows you splitting table as well but there are some problems when you split table to more than two entities (I think it requires each entity type to have navigation property to all other entity types from split table - that makes it really hard to use).
Create stored procedures that query the number of columns needed and then call the stored procs from code.
Background is the team i'm in has just started using the EntityFramework; first we designed the database, put all the table relationships in place, foreign keys, etc; then thru visual studio add a new ADO.NET Entity Data Model, and auto-magically we get the generated edmx file representing the whole database !
Now i focus on two tables that provide data for all dropdowns and lookup lists;
TLookupDomain (domainID, domainName, domainDesc )
TLookup (lookupID, domainID, lookupCode, lookupDisplay, lookupDesc, sortOrder)
Relationship is 1-M going from left to right:
TLookupDomain -< TLookup -< TOther (+ another 30 or so other tables)
So lookupID is a foreign-Key to as many as 30 tables;
IQueryable<TLookup> qList = from l in ctx.TLookups
where l.domainID == 24
select l;
foreach (TLookup l in qList)
{
//do something.
System.Diagnostics.Debug.WriteLine("{0}\t{1}", l.lookupCode, l.lookupDisplay);
foreach (TOther f in l.TOthers)
{
System.Diagnostics.Debug.WriteLine("{0}\t{1}", f.feeAmount, f.feeDesc);
}
}
When i execute the above LINQ, i get all the fields for TLookup table (which is fair), BUT data is also fetched for the 30 or so tables that are linked to it, even though i am NOT interested in the other table's data at this point, and i am going to discard all data soon as LINQ fetches it.
Two Questions i have:
Q.1) Can i somehow modify the LINQ query above or tell the EntityFramework otherwise not to bother fetchin data from the 30 other linked tables ?
Q.2) is it "right" to have one edmx file that models the entire database? (sounds dodgy to me).
Configure Lazy Load to true for the model. Relations should be loaded only upon navegation. You can also split the models to avoid too many unnecessary relations.
Linq-to-Entities queries do not fetch anything automatically. Fetching of navigation properties is performet either by eager or lazy loading. You are not using eager loading because that requires calling Include in query (or ctx.LoadProperty separately). So if your data are fetched it must be due to lazy loading wich is enabled by default. Lazy loading triggers once you access the navigation property in the code.
You can also return only the data you need by using projections. Something like this should return readonly data:
var query = from l in ctx.TLookups
where l.domainId == 24
select new
{
l.lookupCode,
l.lookupDisplay,
l.TOthers
};
Having one or more EDMX is common dilemma. Working with single EDMX makes things more simple. If you want to know how to use multiple EDMXs and share conceptual definitions check these two articles: Part 1, Part 2.
I am having trouble getting Entity Framework 4 to handle a bulk update in a m2m join. I have several many to many joins in my model, for example something like
Practice
PracticeID PK
Name...
PracticeSpecialties (join table)
PracticeID PK
SpecialtyID PK
Specialties
SpecialtyID pk
Name...
Pretty basic and EF 4 handles it well. My problem is I need to be able to "merge" 2 or more Specialties into 1, for example "Pediatrics" and "Children" and "Adolescents" should all be the same item. So if Pediatrics has a SpecialtyID of 1 and Children = 3 and Adolescents = 9 the query should perform an update on all rows in PracticeSpecialties where SpecialtyID IN (3, 9) and change the value to 1.
I can write a stored proc that would update do this all rows in the join table containing one of the undesired SpecialtyIDs then delete all the now orphaned Specialties, but if possible I am trying to stick with the EF pattern.
Any guidance is appreciated.
In entity framework you must do it in object way = you can simply modify junction table. You must work with objects in navigation properties. Your scenario will look like:
var children = context.Specialities.Include("Practices")
.Single(s => s.Name == "Children");
var pediatrics = context.Specialities.Include("Practices")
.Single(s => s.Name == "Pediatrics");
foreach (var practice in children.Practices)
{
pediatrics.Practices.Add(practice);
}
children.Practices.Clear();
context.Specialities.DeleteObject(children);
context.SaveChanges();
You should also override Equals and GetHashCode in Practice entity and use HashSet for Speciality.Practices (in case of POCOs). It will handle duplicities for you.
Result of this will be multiple deletes and inserts to junction table. This is EF way to do that.
Do not use many-to-many relationships. The join table ends up holding more data eventually anyway. Use a one-to-many and a many-to-one combination instead. If you want, you can make a property that holds the created/modified dates in the middle entity for now.
Hope this helps.