Efcore: How should I listen for entities being added/deleted/modified in ef core?

Created on 4 Jul 2016  路  3Comments  路  Source: dotnet/efcore

@rowanmiller

closed-duplicate

Most helpful comment

@Kagamine There isn't public API to do this in EFCore 1.0. This is being tracked by #626.

However, you can do it by accessing our internal services. But be aware that we may change these APIs in future releases which may cause your application to break when updated to a new version of EF. That being said, if you are okay with it, then here is a small console app showing how to do in 1.0:

``` C#
public class StateListener : IEntityStateListener
{
public void StateChanging(InternalEntityEntry entry, EntityState newState)
{
Console.WriteLine(
" Changing {0} from {1} to {2}.",
entry.Entity.GetType().Name, entry.EntityState, newState);
}

public void StateChanged(InternalEntityEntry entry, EntityState oldState, bool skipInitialFixup, bool fromQuery)
{
    Console.WriteLine(
        "  Changed {0} from {1} to {2}.",
        entry.Entity.GetType().Name, oldState, entry.EntityState);
}

}

public class MyContext : DbContext
{
private static readonly IServiceProvider _serviceProvider
= new ServiceCollection()
.AddEntityFrameworkSqlServer()
.AddSingleton(new StateListener())
.BuildServiceProvider();

public DbSet<Blog> Blogs { get; set; }

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder
        .UseInternalServiceProvider(_serviceProvider)
        .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=ListenerTest;Trusted_Connection=True;");

}

public class Blog
{
public int Id { get; set; }
public string Title { get; set; }
}

public class Program
{
public static void Main()
{
using (var context = new MyContext())
{
context.Database.EnsureCreated();

        var blog = new Blog() { Title = "Blog Titlle" };

        Console.WriteLine("Adding...");
        context.Add(blog);

        Console.WriteLine("Saving...");
        context.SaveChanges();
        blog.Title = "Changed Title";

        Console.WriteLine("Detecting change...");
        context.ChangeTracker.DetectChanges();

        Console.WriteLine("Saving...");
        context.SaveChanges();
    }
}

}
```

Things to note here:

  • You need a class that implements IEntityStateListener. This will get the notifications
  • This class must be registered in the dependency injection container. In the example I am adding a single instance to the D,I, container, but how you do it in your app depends on how you ultimately need to use the notifications.
  • You need to tell EF to use the service provider created from this D.I. container. I am creating a static instance of the service provider and registering it in OnConfiguring. If you are using ASP.NET then you will likely want to do this in AddDbContext instead.

Hope this helps. I'm going to close this issue as a dupe of #626.

All 3 comments

@Kagamine There isn't public API to do this in EFCore 1.0. This is being tracked by #626.

However, you can do it by accessing our internal services. But be aware that we may change these APIs in future releases which may cause your application to break when updated to a new version of EF. That being said, if you are okay with it, then here is a small console app showing how to do in 1.0:

``` C#
public class StateListener : IEntityStateListener
{
public void StateChanging(InternalEntityEntry entry, EntityState newState)
{
Console.WriteLine(
" Changing {0} from {1} to {2}.",
entry.Entity.GetType().Name, entry.EntityState, newState);
}

public void StateChanged(InternalEntityEntry entry, EntityState oldState, bool skipInitialFixup, bool fromQuery)
{
    Console.WriteLine(
        "  Changed {0} from {1} to {2}.",
        entry.Entity.GetType().Name, oldState, entry.EntityState);
}

}

public class MyContext : DbContext
{
private static readonly IServiceProvider _serviceProvider
= new ServiceCollection()
.AddEntityFrameworkSqlServer()
.AddSingleton(new StateListener())
.BuildServiceProvider();

public DbSet<Blog> Blogs { get; set; }

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder
        .UseInternalServiceProvider(_serviceProvider)
        .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=ListenerTest;Trusted_Connection=True;");

}

public class Blog
{
public int Id { get; set; }
public string Title { get; set; }
}

public class Program
{
public static void Main()
{
using (var context = new MyContext())
{
context.Database.EnsureCreated();

        var blog = new Blog() { Title = "Blog Titlle" };

        Console.WriteLine("Adding...");
        context.Add(blog);

        Console.WriteLine("Saving...");
        context.SaveChanges();
        blog.Title = "Changed Title";

        Console.WriteLine("Detecting change...");
        context.ChangeTracker.DetectChanges();

        Console.WriteLine("Saving...");
        context.SaveChanges();
    }
}

}
```

Things to note here:

  • You need a class that implements IEntityStateListener. This will get the notifications
  • This class must be registered in the dependency injection container. In the example I am adding a single instance to the D,I, container, but how you do it in your app depends on how you ultimately need to use the notifications.
  • You need to tell EF to use the service provider created from this D.I. container. I am creating a static instance of the service provider and registering it in OnConfiguring. If you are using ASP.NET then you will likely want to do this in AddDbContext instead.

Hope this helps. I'm going to close this issue as a dupe of #626.

Wow! Thanks!

Was this page helpful?
0 / 5 - 0 ratings