use*_*618 6 c# primary-key entity-framework-4
我遵循实体框架示例:
http://msdn.microsoft.com/en-us/library/bb399182.aspx
我有身份列的问题.
以下是创建数据库的代码的一部分:
CREATE TABLE [dbo].[Person](
[PersonID] [int] IDENTITY(1,1) NOT NULL,
[LastName] [nvarchar](50) NOT NULL,
[FirstName] [nvarchar](50) NOT NULL,
[HireDate] [datetime] NULL,
[EnrollmentDate] [datetime] NULL,
CONSTRAINT [PK_School.Student] PRIMARY KEY CLUSTERED
(
[PersonID] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
END
GO
Run Code Online (Sandbox Code Playgroud)
在VS 2010中,我构建了.edmx,在模型中我看到Person StoreGeneratedPattern设置为Identity.
但是当我想创建Person时,通过:

为什么我必须输入id,如果这个列是自动增量?
EDITŁ
我以为我找到了解决问题的方法:
var schoolContext = new SchoolEntities();
schoolContext.AddToPeople(new Person() { LastName = "Gates", FirstName = "Bil" });
schoolContext.SaveChanges();
Run Code Online (Sandbox Code Playgroud)
因为它将Bill添加到了人,但是......因为PersonID不可为空,并且它插入了id为0.当我尝试以同样的方式添加另一个人时,我得到关于主键的错误:)
所以仍然没有......
有任何想法吗 ?
即使生成了ID,也需要IMO.假设您正在使用外键关联(与独立关联不同的行为).这意味着相关子实体正在使用父实体的主键来构建关系.现在假设您在单个工作单元中添加了多个具有相关实体的父实体.您必须为每个父实体指定唯一(临时)ID,否则您将永远不会配置对象图.所以代码生成器可能会将其设置为默认值.
编辑:
令我感到惊讶的是,根据正确的事实,我已被投票支持回答.那么让我澄清一下我的答案:
EF 4.0中有两种类型的关系.独立协会和外键协会.不同之处在于后者将外键属性添加到实体.这允许您以与数据库相同的方式处理关系 - 只需设置键即可.您可以在MSDN中阅读有关这些差异的信息.
现在让我们假设简单的例子 我有MyContext的简单EDMX模型.模型由两个实体Order和OrderLine组成.当我将Orders和OrderLines表添加到模型时,我加粗了在模型中包含外键列,因此我使用外键关联而不是独立关联.
Order将商店生成的Id作为键,将CustomerName作为属性.订单行将商店生成的Id作为键,将ProductTitle作为属性,将OrderId作为外键.我想在单个工作单元中添加两个订单:
using (var context = new MyContext())
{
var ox = Order.CreateOrder(0, "CustomerX");
var oy = Order.CreateOrder(0, "CustomerY");
// Building relationship in the same way as in database
var olx = OrderLine.CreateOrderLine(0, ox.Id, "ProductX");
var oly = OrderLine.CreateOrderLine(0, oy.Id, "ProductY");
context.Orders.AddObject(ox);
context.Orders.AddObject(oy);
context.OrderLines.AddObject(olx);
context.OrderLines.AddObject(oly);
context.SaveChanges(); // UpdateException: Unable determine principal end of Model.FK_OrderLine_Order relationship. Multiple added entities have the same primary key.
}
Run Code Online (Sandbox Code Playgroud)
我在代码中所犯的错误是将两个新订单的Id设置为0.即使这是临时Id,如果要将其用于外键,它仍然必须是唯一的.您现在可能会问为什么上下文不能单独处理Id?很简单,因为它不能.Context知道Id是临时的,并且将在存储中重新生成,但上下文不知道有关存储配置的详细信息.在数据库中设置Identity时,还可以设置种子和增量.上下文不知道这两个值,因此上下文无法派生商店尚未使用的有效唯一临时Id.假设上下文错误地创建了一些临时Id,然后加载已经使用此Id =问题的实体.
如果我只是更新我的代码以使用唯一的临时Id(我知道如何配置商店)它将工作.这是IMO为什么我需要提供临时Id来创建方法的一个原因.
我不能告诉你为什么EF团队选择这样做 - 我唯一的猜测是创建CreatePerson方法的代码生成不会检查ID是否是自动增量并且只是创建一个可以工作的方法在任何情况下 - ID是否自动增量.
如果这真的困扰你,你也可以从生成的实体类Person被定义为部分类的事实中受益,因此你可以轻松地扩展它.创建一个名为eg的新类文件PersonEx.cs并扩展该partial类:
public partial class Person
{
public static Person CreatePerson(string lastName, string firstName)
{
return CreatePerson(-1, lastName, firstName);
}
}
Run Code Online (Sandbox Code Playgroud)
现在,您可以轻松创建Person实体而无需指定ID,并将它们添加到您的数据中:
using(SchoolEntities context = new SchoolEntities())
{
Person newPerson = Person.CreatePerson("Gates", "Bill");
context.AddToPeople(newPerson);
context.SaveChanges();
int newID = newPerson.PersonID;
}
Run Code Online (Sandbox Code Playgroud)
这不是一个完美的解决方案 - 但它应该工作得很好(至少它对我有用).