You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
201 lines
6.6 KiB
C#
201 lines
6.6 KiB
C#
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
|
|
using System;
|
|
using System.Linq;
|
|
using EntityFrameworkCore.Jet.FunctionalTests.TestUtilities;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.EntityFrameworkCore.TestUtilities;
|
|
using Xunit;
|
|
|
|
// ReSharper disable ParameterOnlyUsedForPreconditionCheck.Local
|
|
// ReSharper disable InconsistentNaming
|
|
namespace EntityFrameworkCore.Jet.FunctionalTests
|
|
{
|
|
public class JetTriggersTest : IClassFixture<JetTriggersTest.JetTriggersFixture>
|
|
{
|
|
public JetTriggersTest(JetTriggersFixture fixture) => Fixture = fixture;
|
|
|
|
private JetTriggersFixture Fixture { get; }
|
|
|
|
[ConditionalFact]
|
|
public void Triggers_run_on_insert_update_and_delete()
|
|
{
|
|
using (var context = CreateContext())
|
|
{
|
|
var product = new Product { Name = "blah" };
|
|
context.Products.Add(product);
|
|
context.SaveChanges();
|
|
|
|
var firstVersion = product.Version;
|
|
var productBackup = context.ProductBackups.AsNoTracking().Single();
|
|
AssertEqual(product, productBackup);
|
|
|
|
product.Name = "fooh";
|
|
context.SaveChanges();
|
|
|
|
Assert.NotEqual(firstVersion, product.Version);
|
|
productBackup = context.ProductBackups.AsNoTracking().Single();
|
|
AssertEqual(product, productBackup);
|
|
|
|
context.Products.Remove(product);
|
|
context.SaveChanges();
|
|
|
|
Assert.Empty(context.Products);
|
|
Assert.Empty(context.ProductBackups);
|
|
}
|
|
}
|
|
|
|
[ConditionalFact]
|
|
public void Triggers_work_with_batch_operations()
|
|
{
|
|
using (var context = CreateContext())
|
|
{
|
|
var productToBeUpdated1 = new Product { Name = "u1" };
|
|
var productToBeUpdated2 = new Product { Name = "u2" };
|
|
context.Products.Add(productToBeUpdated1);
|
|
context.Products.Add(productToBeUpdated2);
|
|
|
|
var productToBeDeleted1 = new Product { Name = "d1" };
|
|
var productToBeDeleted2 = new Product { Name = "d2" };
|
|
context.Products.Add(productToBeDeleted1);
|
|
context.Products.Add(productToBeDeleted2);
|
|
|
|
context.SaveChanges();
|
|
|
|
var productToBeAdded1 = new Product { Name = "a1" };
|
|
var productToBeAdded2 = new Product { Name = "a2" };
|
|
context.Products.Add(productToBeAdded1);
|
|
context.Products.Add(productToBeAdded2);
|
|
|
|
productToBeUpdated1.Name = "n1";
|
|
productToBeUpdated2.Name = "n2";
|
|
|
|
context.Products.Remove(productToBeDeleted1);
|
|
context.Products.Remove(productToBeDeleted2);
|
|
|
|
context.SaveChanges();
|
|
|
|
var productBackups = context.ProductBackups.ToList();
|
|
Assert.Equal(4, productBackups.Count);
|
|
|
|
AssertEqual(productToBeAdded1, productBackups.Single(p => p.Name == "a1"));
|
|
AssertEqual(productToBeAdded2, productBackups.Single(p => p.Name == "a2"));
|
|
AssertEqual(productToBeUpdated1, productBackups.Single(p => p.Name == "n1"));
|
|
AssertEqual(productToBeUpdated2, productBackups.Single(p => p.Name == "n2"));
|
|
|
|
context.Products.RemoveRange(context.Products);
|
|
|
|
context.SaveChanges();
|
|
}
|
|
}
|
|
|
|
private static void AssertEqual(Product product, ProductBackup productBackup)
|
|
{
|
|
Assert.Equal(product.Id, productBackup.Id);
|
|
Assert.Equal(product.Name, productBackup.Name);
|
|
Assert.Equal(product.Version, productBackup.Version);
|
|
}
|
|
|
|
protected TriggersContext CreateContext() => (TriggersContext)Fixture.CreateContext();
|
|
|
|
protected class TriggersContext : PoolableDbContext
|
|
{
|
|
public TriggersContext(DbContextOptions options)
|
|
: base(options)
|
|
{
|
|
}
|
|
|
|
public virtual DbSet<Product> Products { get; set; }
|
|
public virtual DbSet<ProductBackup> ProductBackups { get; set; }
|
|
|
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
|
{
|
|
modelBuilder.Entity<Product>(
|
|
eb =>
|
|
{
|
|
eb.Property(e => e.Version)
|
|
.ValueGeneratedOnAddOrUpdate()
|
|
.IsConcurrencyToken();
|
|
eb.Ignore(e => e.StoreUpdated);
|
|
});
|
|
|
|
modelBuilder.Entity<ProductBackup>()
|
|
.Property(e => e.Id).ValueGeneratedNever();
|
|
}
|
|
}
|
|
|
|
protected class Product
|
|
{
|
|
public virtual int Id { get; set; }
|
|
public virtual byte[] Version { get; set; }
|
|
public virtual string Name { get; set; }
|
|
public virtual int StoreUpdated { get; set; }
|
|
}
|
|
|
|
protected class ProductBackup
|
|
{
|
|
public virtual int Id { get; set; }
|
|
public virtual byte[] Version { get; set; }
|
|
public virtual string Name { get; set; }
|
|
}
|
|
|
|
public class JetTriggersFixture : SharedStoreFixtureBase<PoolableDbContext>
|
|
{
|
|
protected override string StoreName { get; } = "JetTriggers";
|
|
protected override Type ContextType { get; } = typeof(TriggersContext);
|
|
protected override ITestStoreFactory TestStoreFactory => JetTestStoreFactory.Instance;
|
|
|
|
protected override void Seed(PoolableDbContext context)
|
|
{
|
|
context.Database.EnsureCreatedResiliently();
|
|
|
|
context.Database.ExecuteSqlRaw(
|
|
@"
|
|
CREATE TRIGGER TRG_InsertProduct
|
|
ON Products
|
|
AFTER INSERT AS
|
|
BEGIN
|
|
IF @@ROWCOUNT = 0
|
|
return
|
|
SET nocount on;
|
|
|
|
INSERT INTO ProductBackups
|
|
SELECT * FROM INSERTED;
|
|
END");
|
|
|
|
context.Database.ExecuteSqlRaw(
|
|
@"
|
|
CREATE TRIGGER TRG_UpdateProduct
|
|
ON Products
|
|
AFTER UPDATE AS
|
|
BEGIN
|
|
IF @@ROWCOUNT = 0
|
|
return
|
|
SET nocount on;
|
|
|
|
UPDATE b
|
|
SET b.Name = p.Name, b.Version = p.Version
|
|
FROM ProductBackups b
|
|
INNER JOIN Products p
|
|
ON b.Id = p.Id
|
|
WHERE p.Id IN(SELECT INSERTED.Id FROM INSERTED);
|
|
END");
|
|
|
|
context.Database.ExecuteSqlRaw(
|
|
@"
|
|
CREATE TRIGGER TRG_DeleteProduct
|
|
ON Products
|
|
AFTER DELETE AS
|
|
BEGIN
|
|
IF @@ROWCOUNT = 0
|
|
return
|
|
SET nocount on;
|
|
|
|
DELETE FROM ProductBackups
|
|
WHERE Id IN(SELECT DELETED.Id FROM DELETED);
|
|
END");
|
|
}
|
|
}
|
|
}
|
|
}
|