我见过这个:
How can you dynamically select a table with entity framework 4.x?
但是我不能在我的情况下使用基类。我希望创建一个用户组和周敏感表进行审计,所以我不知道在运行时创建它们之前会调用它们。
因此,如果我在一年中的第一周登录,那将是:
Group1_01_2014
这可能吗?我试图在创建时简单地更改数据库名称,但是我得到了有关数据库迁移的标准异常。
感谢。
编辑:在有人说拆分数据库之前很傻,知道我正在审核ALOT。我们的想法是能够审核大多数交易,只要需要存储它们,而不会严重影响性能。
Edit2:如果有人有更好的解决方案,那我就听见了。
解决方案
使用存储过程结束:。
CREATE FUNCTION GetAuditTableName
(
@db_code CHAR (4)
)
RETURNS CHAR (12)
BEGIN
DECLARE @wkNo CHAR (2)
DECLARE @year CHAR (4)
SELECT @wkNo = REPLACE(STR(DATEPART(WEEK, GETDATE()), 2), SPACE(1), '0')
SELECT @year = STR(DATEPART(YEAR, GETDATE()), 4)
RETURN @db_code + '_' + @year + '_' + @wkNo
END
GO
CREATE PROCEDURE [dbo].[Audit_Insert]
@audi_id_first NVARCHAR (20),
@audi_id_second NVARCHAR (20),
@audi_by NVARCHAR (100),
@audi_on DATETIME,
@audi_details XML,
@tabn_code CHAR (4),
@audt_id INT,
@audi_db_code CHAR (4)
AS
BEGIN
DECLARE @tableName CHAR (12)
SET @tableName = [dbo].GetAuditTableName(@audi_db_code)
IF NOT EXISTS (SELECT * FROM sysobjects WHERE name=@tableName and xtype='U')
BEGIN
DECLARE @createSql NVARCHAR(MAX);
SELECT @createSql = 'CREATE TABLE [dbo].' + QUOTENAME(@tableName) + ' (
[audi_id] INT IDENTITY (1, 1) NOT NULL,
[audi_id_first] NVARCHAR (20) NULL,
[audi_id_second] NVARCHAR (20) NULL,
[audi_by] NVARCHAR (100) NOT NULL,
[audi_on] DATETIME NOT NULL,
[audi_details] XML NULL,
[tabn_code] CHAR (4) NULL,
[audt_id] INT NOT NULL,
CONSTRAINT [PK_dbo.' + @tableName + '] PRIMARY KEY CLUSTERED ([audi_id] ASC),
CONSTRAINT [FK_dbo.' + @tableName + '_dbo.tabn_table_name_tabn_code] FOREIGN KEY ([tabn_code]) REFERENCES [dbo].[tabn_table_name] ([tabn_code]),
CONSTRAINT [FK_dbo.' + @tableName + '_dbo.audt_audit_type_audt_id] FOREIGN KEY ([audt_id]) REFERENCES [dbo].[audt_audit_type] ([audt_id])
)'
EXEC sp_executesql @createSql
END
DECLARE @insertSql NVARCHAR(MAX);
SELECT @insertSql = N'INSERT [dbo].' + QUOTENAME(@tableName) + ' ([audi_id_first], [audi_id_second], [audi_by], [audi_on], [audi_details], [tabn_code], [audt_id])
VALUES (@audi_id_first, @audi_id_second, @audi_by, @audi_on, @audi_details, @tabn_code, @audt_id)'
EXEC sp_executesql @insertSql, N'@audi_id_first NVARCHAR (20), @audi_id_second NVARCHAR (20), @audi_by NVARCHAR (100), @audi_on DATETIME, @audi_details XML, @tabn_code CHAR (4), @audt_id INT', @audi_id_first, @audi_id_second, @audi_by, @audi_on, @audi_details, @tabn_code, @audt_id
DECLARE @idSql NVARCHAR(MAX);
SELECT @idSql = 'DECLARE @audi_id INT
SELECT @audi_id = [audi_id]
FROM [dbo].' + QUOTENAME(@tableName) + '
WHERE @@ROWCOUNT > 0 AND [audi_id] = scope_identity()
SELECT t0.[audi_id]
FROM [dbo].' + QUOTENAME(@tableName) + ' AS t0
WHERE @@ROWCOUNT > 0 AND t0.[audi_id] = @audi_id'
EXEC sp_executesql @idSql
END
GO
然后从C#中调用它:
public void AddRecord(Audit record)
{
var Id1 = new SqlParameter("@audi_id_first", SqlDbType.NVarChar);
Id1.Value = (object)record.Id1 ?? System.DBNull.Value;
var Id2 = new SqlParameter("@audi_id_second", SqlDbType.NVarChar);
Id2.Value = (object)record.Id2 ?? System.DBNull.Value;
var UserName = new SqlParameter("@audi_by", SqlDbType.NVarChar);
UserName.Value = record.UserName;
var Stamp = new SqlParameter("@audi_on", SqlDbType.DateTime);
Stamp.Value = record.Stamp;
var Details = new SqlParameter("@audi_details", SqlDbType.Xml);
Details.Value = (object)record.Details ?? System.DBNull.Value;
var TableCode = new SqlParameter("@tabn_code", SqlDbType.Char);
TableCode.Value = record.TableCode;
var TypeId = new SqlParameter("@audt_id", SqlDbType.Int);
TypeId.Value = record.TypeId;
var DatabaseCode = new SqlParameter("@audi_db_code", SqlDbType.Char);
DatabaseCode.Value = CallingPrefix;
this.Database.ExecuteSqlCommand("EXEC Audit_Insert @audi_id_first, @audi_id_second, @audi_by, @audi_on, @audi_details, @tabn_code, @audt_id, @audi_db_code",
Id1, Id2, UserName, Stamp, Details, TableCode, TypeId, DatabaseCode);
}
我的下一步努力是让它与IQueryable OData请求一起使用。
解决方案2
CREATE PROCEDURE [dbo].[CreateAuditTableIfNoneExists]
@tableName CHAR (12)
AS
BEGIN
IF NOT EXISTS (SELECT * FROM sysobjects WHERE name=@tableName and xtype='U')
BEGIN
DECLARE @createSql NVARCHAR(MAX);
SELECT @createSql = 'CREATE TABLE [dbo].' + QUOTENAME(@tableName) + ' (
[audi_id] INT IDENTITY (1, 1) NOT NULL,
[audi_id_first] NVARCHAR (20) NULL,
[audi_id_second] NVARCHAR (20) NULL,
[audi_by] NVARCHAR (100) NOT NULL,
[audi_on] DATETIME NOT NULL,
[audi_details] XML NULL,
[tabn_code] CHAR (4) NULL,
[audt_id] INT NOT NULL,
CONSTRAINT [PK_dbo.' + @tableName + '] PRIMARY KEY CLUSTERED ([audi_id] ASC),
CONSTRAINT [FK_dbo.' + @tableName + '_dbo.tabn_table_name_tabn_code] FOREIGN KEY ([tabn_code]) REFERENCES [dbo].[tabn_table_name] ([tabn_code]),
CONSTRAINT [FK_dbo.' + @tableName + '_dbo.audt_audit_type_audt_id] FOREIGN KEY ([audt_id]) REFERENCES [dbo].[audt_audit_type] ([audt_id])
)'
EXEC sp_executesql @createSql
END
END
并在数据库初始化时确保该表存在:
public class AuditInitialiser : IDatabaseInitializer<AuditContext>
{
public void InitializeDatabase(AuditContext context)
{
if (context.Database.CreateIfNotExists())
{
Seed(context);
}
var tableName = new SqlParameter("@tableName", SqlDbType.Char);
tableName.Value = context.AuditTableName;
context.Database.ExecuteSqlCommand("EXEC CreateAuditTableIfNoneExists @tableName", tableName);
}
然而,这只适用于我,因为我使用的是API,因此无状态并且每次都构造DbContext。这可确保表始终存在。如果我在一个规定的系统上工作,那就行不通了。
答案 0 :(得分:2)
我不是存储过程的忠实粉丝,但这可能是您希望使用EF 6(EF5 ??)绑定到存储过程的能力的情况。然后您可以传递表以用作参数。看看这是否有帮助:How to call Stored Procedure in Entity Framework 6 (Code-First)?
(您也可以使用EntitySQL来解决此问题)