EF 4中的标识列

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.当我尝试以同样的方式添加另一个人时,我得到关于主键的错误:)

所以仍然没有......

有任何想法吗 ?

Lad*_*nka 7

即使生成了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来创建方法的一个原因.


mar*_*c_s 6

我不能告诉你为什么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)

这不是一个完美的解决方案 - 但它应该工作得很好(至少它对我有用).