Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DbContext throws exception on query when accessed through interface

I have created an interface that my DbContext class implements, this enables me to create a fake db context for unit testing. This works well for all my LINQ queries so far but one, where I get the following exception:

Unable to create a constant value of type 'DemoApp.Member'. Only primitive types ('such as Int32, String, and Guid') are supported in this context.

Executing the LINQ query through the interface throws the above exception, however when executing the exact same query directly on my DBContext the query works 100%. Here is the interface and related demo code definitions:

    interface IDemoContext : IDisposable
{
    IDbSet<Member> Members { get; set; }
    IDbSet<Team> Teams { get; set; }
}

public partial class DemoContext : DbContext, IDemoContext
{
    public DemoContext() : base("name=DemoContext"){}

    public IDbSet<Member> Members { get; set; }
    public IDbSet<Team> Teams { get; set; }
}

public partial class Member
{
    public Member()
    {
        this.SecondaryTeams = new HashSet<Team>();
    }

    public int ID { get; set; }
    public string Name { get; set; }
    public int? PrimaryTeamID { get; set; }

    public virtual Team PrimaryTeam { get; set; }
    public virtual ICollection<Team> SecondaryTeams { get; set; }
}

public partial class Team
{
    public Team()
    {
        this.PrimaryMembers = new HashSet<Member>();
        this.SecondaryMembers = new HashSet<Member>();
    }

    public int ID { get; set; }
    public string Name { get; set; }

    public virtual ICollection<Member> PrimaryMembers { get; set; }
    public virtual ICollection<Member> SecondaryMembers { get; set; }
}

Each member potentially belongs to a single primary team, and optionally many secondary teams. The following demo code throws the exception:

using (IDemoContext dbi = new DemoContext())
        {
            var members =
                (from member in dbi.Members
                select new
                {
                    Name = member.Name,
                    Team = member.PrimaryTeam.Name,
                    SecondaryTeams = from secondaryTeam in member.SecondaryTeams
                        join primaryMember in dbi.Members
                        on secondaryTeam.ID equals primaryMember.PrimaryTeamID
                        into secondaryTeamMembers
                        select new
                        {
                            Name = secondaryTeam.Name,
                            Count = secondaryTeamMembers.Count()
                        }
                }).ToList();
        }

If I change the first line to:

using (DemoContext dbi = new DemoContext())

then the query executes perfectly.

So my questions are:

  1. Why does it work through DemoContext and not IDemoContext?
  2. How do I change IDemoContext so this query does work through the interface?
like image 562
Beyers Avatar asked Jan 19 '12 23:01

Beyers


People also ask

What is DbContext and DbSet in Entity Framework?

DbContext generally represents a database connection and a set of tables. DbSet is used to represent a table. Your code sample doesn't fit the expected pattern. First, it is incomplete. Also, there are properties that really don't belong.

What does DbContext class do?

A DbContext instance represents a combination of the Unit Of Work and Repository patterns such that it can be used to query from a database and group together changes that will then be written back to the store as a unit. DbContext is conceptually similar to ObjectContext.

What is a database context?

A DbContext instance represents a session with the database and can be used to query and save instances of your entities. DbContext is a combination of the Unit Of Work and Repository patterns. Entity Framework Core does not support multiple parallel operations being run on the same DbContext instance.


1 Answers

Try replacing dbi.Members with a local variable in the query.

    using (IDemoContext dbi = new DemoContext())
    {
        IQueryable<Member> memberSet = dbi.Members;

        var members =
            (from member in memberSet
            select new
            {
                Name = member.Name,
                Team = member.PrimaryTeam.Name,
                SecondaryTeams = from secondaryTeam in member.SecondaryTeams
                    join primaryMember in memberSet
                    on secondaryTeam.ID equals primaryMember.PrimaryTeamID
                    into secondaryTeamMembers
                    select new
                    {
                        Name = secondaryTeam.Name,
                        Count = secondaryTeamMembers.Count()
                    }
            }).ToList();
    }
like image 194
Eranga Avatar answered Oct 16 '22 04:10

Eranga