我可以在SQL Server 2016中使用时态表.遗憾的是,Entity Framework 6还不知道这个功能.是否有可能使用实体框架6 使用新的查询选项(请参阅msdn)?
我创建了一个带有员工时态表的简单演示项目:
我使用edmx将表映射到实体(感谢Matt Ruwe):
使用纯sql语句一切正常:
using (var context = new TemporalEntities())
{
var employee = context.Employees.Single(e => e.EmployeeID == 2);
var query =
$@"SELECT * FROM [TemporalTest].[dbo].[{nameof(Employee)}]
FOR SYSTEM_TIME BETWEEN
'0001-01-01 00:00:00.00' AND '{employee.ValidTo:O}'
WHERE EmployeeID = 2";
var historyOfEmployee = context.Employees.SqlQuery(query).ToList();
}
Run Code Online (Sandbox Code Playgroud)
是否可以在没有纯SQL的情况下将历史记录功能添加到每个实体?我的解决方案作为实体扩展与反射来操纵SQL查询IQuerable并不完美.是否有现有的扩展或库来执行此操作?
编辑:(基于Pawel的评论)
我试图使用表值函数:
CREATE FUNCTION dbo.GetEmployeeHistory(
@EmployeeID int,
@startTime datetime2,
@endTime datetime2)
RETURNS TABLE
AS
RETURN
(
SELECT
EmployeeID,
[Name],
Position,
Department,
[Address], …Run Code Online (Sandbox Code Playgroud) 我正在使用数据库第一实体框架6.在将我的模式中的一些表更改为临时表后,我在尝试插入新数据时开始收到以下错误:
Cannot insert an explicit value into a GENERATED ALWAYS column in table '<MyDatabase>.dbo.<MyTableName>. Use INSERT with a column list to exclude the GENERATED ALWAYS column, or insert a DEFAULT into GENERATED ALWAYS column.
看起来EF正在尝试更新PERIOD由系统管理的列的值.
从EDMX文件中删除列似乎可以解决问题,但这不是一个可行的解决方案,因为每次从数据库重新生成模型时都会重新添加列.
c# sql-server temporal-database entity-framework-6 sql-server-2016
该IDbCommandInterceptor接口是不是非常有据可查.我只发现了一些稀缺的教程:
还有一些问题:
这些是关于挂钩的建议我发现:
1 - 静态DbInterception类:
DbInterception.Add(new MyCommandInterceptor());
Run Code Online (Sandbox Code Playgroud)
2 - 在DbConfiguration课堂上做上述建议
public class MyDBConfiguration : DbConfiguration {
public MyDBConfiguration() {
DbInterception.Add(new MyCommandInterceptor());
}
}
Run Code Online (Sandbox Code Playgroud)
3 - 使用配置文件:
<entityFramework>
<interceptors>
<interceptor type="EFInterceptDemo.MyCommandInterceptor, EFInterceptDemo"/>
</interceptors>
</entityFramework>
Run Code Online (Sandbox Code Playgroud)
虽然我无法弄清楚如何将DbConfiguration类挂钩到DbContext,并且既没有放入typeconfig方法的部分.我发现的另一个例子似乎建议您编写记录器的命名空间:
type="System.Data.Entity.Infrastructure.Interception.DatabaseLogger, EntityFramework"
Run Code Online (Sandbox Code Playgroud)
我注意到了DataBaseLogger工具IDisposable,IDbConfigurationInterceptor和
IDbInterceptor.IDbCommandInterceptor也实现了IDbInterceptor,所以我尝试(没有成功)格式化它像这样:
type="DataLayer.Logging.MyCommandInterceptor, DataLayer"
Run Code Online (Sandbox Code Playgroud)
当我DbInterception直接调用静态类时,它每次调用都会添加另一个拦截器.所以我的快速而肮脏的解决方案是利用静态构造函数:
//This partial class is …Run Code Online (Sandbox Code Playgroud) 我正在使用一个IDbCommandInterceptor实现:
public class MyInterceptor : IDbCommandInterceptor\n{\n public void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)\n {\n var context = interceptionContext.DbContexts.FirstOrDefault();\n }\n\n public void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext<int> interceptionContext)\n {\n }\n\n public void ScalarExecuting(DbCommand command, DbCommandInterceptionContext<object> interceptionContext)\n {\n }\n\n public void NonQueryExecuted(DbCommand command, DbCommandInterceptionContext<int> interceptionContext)\n {\n }\n\n public void ReaderExecuted(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)\n {\n }\n\n public void ScalarExecuted(DbCommand command, DbCommandInterceptionContext<object> interceptionContext)\n {\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n\n以此注入:
\n\npublic class TestContext : System.Data.Entity.DbContext\n{\n // \xe2\x80\xa6\n\n public TestContext()\n : base("TestConnectionString")\n {\n Database.SetInitializer<TestContext>(null);\n DbInterception.Add(new MyInterceptor());\n }\n}\n …Run Code Online (Sandbox Code Playgroud)