【发布时间】:2018-04-02 02:47:15
【问题描述】:
我将 Entity Framework 6 DB First 与 SQL Server 表一起使用,每个表都有一个 uniqueidentifier 主键。这些表在主键列上有一个默认值,将其设置为newid()。我相应地更新了我的 .edmx 以将这些列的 StoreGeneratedPattern 设置为 Identity。所以我可以创建新记录,将它们添加到我的数据库上下文中,然后自动生成 ID。但是现在我需要保存一个具有特定 ID 的新记录。我读过this article,它说在使用int identity PK 列时必须在保存之前执行SET IDENTITY_INSERT dbo.[TableName] ON。由于我的是 Guid 而不是实际的身份列,因此基本上已经完成了。然而,即使在我的 C# 中我将 ID 设置为正确的 Guid,该值甚至不会作为参数传递给生成的 SQL 插入,并且 SQL Server 会为主键生成一个新的 ID。
我需要两者兼得:
- 插入一条新记录,让它自动创建ID,
- 插入具有指定 ID 的新记录。
我有#1。如何插入具有特定主键的新记录?
编辑:
保存代码摘录(注意 accountMemberSpec.ID 是我想成为 AccountMember 主键的具体 Guid 值):
IDbContextScopeFactory dbContextFactory = new DbContextScopeFactory();
using (var dbContextScope = dbContextFactory.Create())
{
//Save the Account
dbAccountMember = CRMEntity<AccountMember>.GetOrCreate(accountMemberSpec.ID);
dbAccountMember.fk_AccountID = accountMemberSpec.AccountID;
dbAccountMember.fk_PersonID = accountMemberSpec.PersonID;
dbContextScope.SaveChanges();
}
--
public class CRMEntity<T> where T : CrmEntityBase, IGuid
{
public static T GetOrCreate(Guid id)
{
T entity;
CRMEntityAccess<T> entities = new CRMEntityAccess<T>();
//Get or create the address
entity = (id == Guid.Empty) ? null : entities.GetSingle(id, null);
if (entity == null)
{
entity = Activator.CreateInstance<T>();
entity.ID = id;
entity = new CRMEntityAccess<T>().AddNew(entity);
}
return entity;
}
}
--
public class CRMEntityAccess<T> where T : class, ICrmEntity, IGuid
{
public virtual T AddNew(T newEntity)
{
return DBContext.Set<T>().Add(newEntity);
}
}
这里是记录的,为此生成的 SQL:
DECLARE @generated_keys table([pk_AccountMemberID] uniqueidentifier)
INSERT[dbo].[AccountMembers]
([fk_PersonID], [fk_AccountID], [fk_FacilityID])
OUTPUT inserted.[pk_AccountMemberID] INTO @generated_keys
VALUES(@0, @1, @2)
SELECT t.[pk_AccountMemberID], t.[CreatedDate], t.[LastModifiedDate]
FROM @generated_keys AS g JOIN [dbo].[AccountMembers] AS t ON g.[pk_AccountMemberID] = t.[pk_AccountMemberID]
WHERE @@ROWCOUNT > 0
-- @0: '731e680c-1fd6-42d7-9fb3-ff5d36ab80d0' (Type = Guid)
-- @1: 'f6626a39-5de0-48e2-a82a-3cc31c59d4b9' (Type = Guid)
-- @2: '127527c0-42a6-40ee-aebd-88355f7ffa05' (Type = Guid)
【问题讨论】:
-
能否包含相关的 C# 代码?
-
添加了主要部分,但我认为用英文阅读更容易。
-
所以我先说 EF 不是我最擅长的。但据我了解,如果您将
StoredGeneratedPattern设置为identity,这告诉EF 它甚至不需要考虑您提供的PK;它将使用数据库服务器来生成值。如果该列已经有默认值newid()或newsequentialid(),您可以尝试将枚举值更改为None并看看会发生什么?我的想法是,这将阻止它假设 SQL 将创建 guid。然后即使您不提供,列默认也会。 -
你是对的,但这也阻止了它同时插入新的父/子记录(没有显式设置它们的 ID。)如果你添加
new Parent()到没有身份DbContext 然后执行 parent.Children.Add(new Child()) 并保存它将在数据库中插入具有 fk_ParentID = "00000000-0000-0000-0000-000000000000" 的孩子,因为它不知道父母的 ID 是生成的标识。做同样的事情,但不要保存添加第二个孩子。现在 DbContext 将抛出一个异常,您尝试添加具有重复主键的子项,即空 Guid -
我知道您可以将实体插入/更新/删除映射到存储过程。对于这种特殊情况,这可能是一个很好的选择。你所做的绝不是常态。您已经创建了一个具有唯一标识符或自动增量字段的表,并将其绑定到您的 EF 工作。它的工作方式与您的数据库设计有关。我认为您不会找到忽略 PK 约束标志或类似的东西。
标签: c# sql sql-server entity-framework guid