Skip to content

Add FK constraint checking to the in-memory provider #2166

Closed as not planned
Closed as not planned
@htuomola

Description

@htuomola

Hi, my apologies if this is already covered by any other open/closed issue but I couldn't find any.
It seems that the In-memory provider is not enforcing required foreign key properties and thus acts differently from SQL Server provider. I'm using build 7.0.0-beta5-13171 (latest nightly).

I suppose this is a known issue? Is there a plan/target for fixing it? I believe unit testing is a big use case for using the in-memory provider but with this kind of limitations, its value is diminished (for now).

Here's sample code to demonstrate this:

[TestMethod]
[ExpectedException(typeof(DbUpdateException))]
public void AddOnlyChild_SQL()
{
    /* This method throws an exception (as it should): 
     * Microsoft.Data.Entity.Update.DbUpdateException: An error occurred while updating the entries. 
     * See the inner exception for details. 
     * ---> System.Data.SqlClient.SqlException: 
     * The INSERT statement conflicted with the FOREIGN KEY constraint "FK_Child_Parent_ParentId". 
     * The conflict occurred in database "EF7Test", table "dbo.Parent", column 'Id'.
     */
    using (var ctx = new SimpleContext())
    {
        AddOnlyChild(ctx);
    }
}

[TestMethod]
[ExpectedException(typeof(DbUpdateException))]
public void AddOnlyChild_InMemory()
{
    // this doesn't throw an exception, thus failing the test 
    var optionsBuilder = new DbContextOptionsBuilder();
    optionsBuilder.UseInMemoryStore();
    using (var ctx = new SimpleContext(optionsBuilder.Options))
    {
        AddOnlyChild(ctx);
    }
}

private static void AddOnlyChild(SimpleContext ctx)
{
    var child = new Child {Name = "Dave", Id = Guid.NewGuid()};
    ctx.Children.Add(child);
    ctx.SaveChanges();
}

Context & model:

public class SimpleContext : DbContext
{
    public SimpleContext() { }

    public SimpleContext(DbContextOptions options) : base(options)  { }

    public DbSet<Parent> Parents { get; set; }
    public DbSet<Child> Children { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        if (!optionsBuilder.IsConfigured)
            optionsBuilder.UseSqlServer(@"Server=(localdb)\v11.0;Database=EF7Test;Trusted_Connection=True;MultipleActiveResultSets=true");
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Child>().Table("Child");

        modelBuilder.Entity<Child>().Key(r => r.Id);

        modelBuilder.Entity<Child>()
            .Property(r => r.Id)
            .GenerateValueOnAdd(true);

        modelBuilder.Entity<Child>()
            .Reference<Parent>(rs => rs.Parent)
            .InverseCollection(r => r.Children)
            .ForeignKey(rs => rs.ParentId)
            .Required();

        // parent model

        modelBuilder.Entity<Parent>().Table("Parent");

        modelBuilder.Entity<Parent>().Key(r => r.Id);

        modelBuilder.Entity<Parent>()
            .Property(r => r.Id)
            .GenerateValueOnAdd(true);
    }
}

public class Parent
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public List<Child> Children { get; set; }
}

public class Child
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public Guid ParentId { get; set; }
    public Parent Parent { get; set; }
}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions