我有一个简单的表,其中包含两个通过触发器更新的字段。
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获取更新的字段而不是强制进行数据库查询吗?
答案 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);
触发器在插入时触发,并自动生成需要生成的字段。