I have two tables:
DocumentSet:
setId (int)
name (varchar(50))
DocIdentifier:
docIdId (int)
docSetId (int) <-- (setId from DocumentSet)
customId (char(9))
The typical queries done on the two tables look like this in SQL:
SELECT ds.name
FROM DocumentSet ds
INNER JOIN DocIdentifiers di ON ds.setId = di.docSetId
WHERE di.customId == 'someId'
Notice the naming difference: setId
and docSetId
are the columns used for the foreign key. The problem comes when I try to replicated this in Entity Framework. I have the obvious models:
class DocumentSet {
public int Id {get;set;}
public string Name {get;set;}
public virtual ICollection<DocumentIdentifier> Identifiers {get;set;}
}
class DocumentIdentifier {
public int Id {get;set;}
public int SetId {get;set;}
public string CustomId {get;set;}
public DocumentSet DocSet {get;set;}
}
Again, some naming differences for clarity in the code. So I create EntityTypeConfiguration
s for both:
internal class DocumentSetTypeConfiguration : EntityTypeConfiguration<DocumentSet> {
public DocumentSetTypeConfiguration () {
HasKey(f => f.Id);
Property(f => f.Id).HasColumnName("setId");
HasMany(f => f.DocumentIdentifiers);
}
}
internal class DocumentIdentifierTypeConfiguration : EntityTypeConfiguration<DocumentIdentifier> {
public DocumentIdentifierTypeConfiguration () {
ToTable("DocIdentifier");
HasKey(f => f.Id);
Property(f => f.Id).HasColumnName("docIdId");
Property(f => f.SetId).HasColumnName("docSetId");
}
}
Here's the problem: When I send a LINQ query like this:
_context.Set<DocumentSet>().Where(d => d.DocumentIdentifiers.Any(pt=>pt.CustomId == customId)).Single();
What's generated gets a little botched:
SELECT TOP (2)
[Extent1].[SetId] AS [SetId],
[Extent1].[Name] AS [Name]
FROM [dbo].[DocumentSet] AS [Extent1]
WHERE EXISTS (SELECT
1 AS [C1]
FROM [dbo].[DocIdentifier] AS [Extent2]
WHERE ([Extent1].[SetId] = [Extent2].[DocumentSet_Id]) AND (([Extent2].CustomId = @p__linq__0) OR (([Extent2].[CustomId] IS NULL) AND (@p__linq__0 IS NULL)))
)
My guess that the problem lies in the fact that setId
and docSetId
are different names, but I can't seem to figure out how to get EF to see that [Extent2].[DocumentSet_Id]
should be [Extent2].[docSet_Id]
. Is there something I'm missing in DocumentIdentifierTypeConfiguration
that will help EF understand this? I thought the line Property(f => f.SetId).HasColumnName("docSetId");
would do this, but apparently not.
In short, how do I say
`DocumentSet has many DocumentIdentifiers with a foreign key relationship of DocumentSet.setId = DocIdentifier.docSetId`?
Try adding WithRequired
and HasForeignKey
.
HasMany(f => f.Identifiers).WithRequired().HasForeignKey(x => x.SetId);
Full Code
public class AppContext : DbContext
{
public DbSet<DocumentSet> DocumentSets { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new DocumentSetTypeConfiguration());
modelBuilder.Configurations.Add(new DocumentIdentifierTypeConfiguration());
}
}
public class DocumentSetTypeConfiguration : EntityTypeConfiguration<DocumentSet>
{
public DocumentSetTypeConfiguration()
{
HasKey(f => f.Id);
Property(f => f.Id).HasColumnName("setId");
HasMany(f => f.DocumentIdentifiers).WithRequired().HasForeignKey(x => x.SetId);
}
}
public class DocumentIdentifierTypeConfiguration : EntityTypeConfiguration<DocumentIdentifier>
{
public DocumentIdentifierTypeConfiguration()
{
ToTable("DocIdentifier");
HasKey(f => f.Id);
Property(f => f.Id).HasColumnName("docIdId");
Property(f => f.SetId).HasColumnName("docSetId");
}
}
public class DocumentSet
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<DocumentIdentifier> DocumentIdentifiers { get; set; }
}
public class DocumentIdentifier
{
public int Id { get; set; }
public int SetId { get; set; }
public string CustomId { get; set; }
}
Database Result
Query Result
SELECT TOP (2)
[Extent1].[setId] AS [setId],
[Extent1].[Name] AS [Name]
FROM [dbo].[DocumentSets] AS [Extent1]
WHERE EXISTS (SELECT
1 AS [C1]
FROM [dbo].[DocIdentifier] AS [Extent2]
WHERE ([Extent1].[setId] = [Extent2].[docSetId])
AND (([Extent2].[CustomId] = @p__linq__0)
OR (([Extent2].[CustomId] IS NULL) AND (@p__linq__0 IS NULL)))
)