EF 6不检索触发更新字段

时间:2014-12-18 14:27:59

标签: entity-framework triggers

我有一个简单的表,其中包含两个通过触发器更新的字段。

CREATE TABLE [dbo].[CarType](
    [idCarType] [int] IDENTITY(1,1) NOT NULL,
    [CarTypeName] [nvarchar](50) NOT NULL,
    [CR_Date] [datetime2](7) NOT NULL CONSTRAINT [DF_CarType_CR_Date]  DEFAULT (getdate()),
    [LU_Date] [datetime2](7) NOT NULL CONSTRAINT [DF_CarType_LU_Date]  DEFAULT (getdate()),
 CONSTRAINT [PK_CarType] PRIMARY KEY CLUSTERED (    [idCarType] ASC)
)
END
GO
EXEC dbo.sp_executesql @statement = N'
CREATE TRIGGER [dbo].[CarType_Insert] ON [dbo].[CarType]
  AFTER INSERT AS 
BEGIN
    UPDATE dbo.CarType
      SET dbo.CarType.CR_Date=getdate(), dbo.CarType.LU_Date=getdate()
         FROM dbo.CarType
         INNER JOIN Inserted ON dbo.CarType.idCarType = Inserted.idCarType
END' 
GO

EXEC dbo.sp_executesql @statement = N'
CREATE TRIGGER [dbo].[CarType_Update] ON [dbo].[CarType]
  AFTER UPDATE AS 
BEGIN
    UPDATE dbo.CarType
      SET  dbo.CarType.LU_Date=getdate()
         FROM dbo.CarType
         INNER JOIN Inserted ON dbo.CarType.idCarType = Inserted.idCarType
END' 
GO

当我使用以下内容添加新内容时:

CarEntities db = new CarEntities();
CarType car = new CarType()
{
  CarTypeName = "Ford"
};
db.CarTypes.Add(carType);
db.SaveChanges();

carType.Dump(); //extension to print out type as JSON

CarType newCar = db.CarTypes.AsNoTracking().Where(e => e.idCarType == carType.idCarType).First();
newCar.Dump(); //extension to print out type as JSON

carType回复为:

{
    "idCarType": 8,
    "CarTypeName": "Ford",
    "CR_Date": "0001-01-01T00:00:00",
    "LU_Date": "0001-01-01T00:00:00"
}

但是newCar回来了:

{
    "idCarType": 8,
    "CarTypeName": "Ford",
    "CR_Date": "2014-12-18T07:53:27.773",
    "LU_Date": "2014-12-18T07:53:27.773"
}

但仅限于我添加AsNoTracking部分。

知道如何使用ADD获取更新的字段而不是强制进行数据库查询吗?

2 个答案:

答案 0 :(得分:3)

当数据库是“愚蠢的”时,实体框架效果最好。并将所有逻辑留给EF代码。当触发器和存储作业等数据库功能对数据进行更改时,实体框架不会知道更改,除非它明确地重新查询数据。因此,您必须编写代码以强制EF在保存数据后刷新数据以进行这些更改。

首先,尝试将CR_Date和LU_Date列配置为数据库生成。

Property(p => p.CR_Date).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed);

但我不确定是否会接收触发器所做的数据更改。如果没有,那么您需要强制重新加载。

为此,请覆盖DbContext类中的SaveChanges方法。获取已添加和修改的条目的列表,让保存继续,然后从数据库强制更新这些条目:

public override int SaveChanges()
{

    var entriesToReload = ChangeTracker.Entries<ITrackedEntity>().Where(e => e.State == EntityState.Added || e.State == EntityState.Modified).ToList();

    int rowCount;
    rowCount = base.SaveChanges();

    if (rowCount > 0)
    {
        entriesToReload.ForEach(e=>e.Reload());
    }

    return rowCount;

}

或者,如果您可以使用仅由EF应用程序使用的数据库,则可以编写将在应用程序而不是数据库触发器中更新CR_Date和LU_Date的EF代码。

首先,创建一个定义更新跟踪字段的界面,并确保包含这些日期的所有实体都实现该界面。

public interface ITrackedEntity
{
    DateTime CR_Date { get; set; }
    DateTime LU_Date { get; set; }
}

然后在您的DbContext类中,您可以覆盖SaveChanges方法并根据它们在ChangeTracker中的状态更新这些字段:

foreach (var entry in ChangeTracker.Entries<ITrackedEntity>())
{

    if (entry.Entity.DataStatus == EntityDataStatus.Added)
    {
        entry.Entity.CR_Date = DateTime.Now;
        entry.Entity.LU_Date = DateTime.Now;
    }
    if (entry.Entity.DataStatus == EntityDataStatus.Modified)
    {
        entry.Entity.LU_Date = DateTime.Now;
    }
}

答案 1 :(得分:0)

我知道此答案已经被接受,但是以上内容对我来说不起作用。

我改为这样做:

    string insertSql=
    "INSERT(fields)VALUES(Myvalues)";

_dbContext.Database.ExecuteSqlCommand(TransactionalBehavior.DoNotEnsureTransaction, sql);

触发器在插入时触发,并自动生成需要生成的字段。