11 c# sql-server asp.net-mvc entity-framework entity-framework-5
我们使用EF5和SQL Server 2012以下两个类:
public class Question
{
public Question()
{
this.Answers = new List<Answer>();
}
public int QuestionId { get; set; }
public string Title { get; set; }
public virtual ICollection<Answer> Answers { get; set; }
}
public class Answer
{
public int AnswerId { get; set; }
public string Text { get; set; }
public int QuestionId { get; set; }
public virtual Question Question { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
映射如下:
public class AnswerMap : EntityTypeConfiguration<Answer>
{
public AnswerMap()
{
// Primary Key
this.HasKey(t => t.AnswerId);
// Identity
this.Property(t => t.AnswerId)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
Run Code Online (Sandbox Code Playgroud)
数据库DDL
CREATE TABLE Answer (
[AnswerId] INT IDENTITY (1, 1) NOT NULL,
[QuestionId] INT NOT NULL,
[Text] NVARCHAR(1000),
CONSTRAINT [PK_Answer] PRIMARY KEY CLUSTERED ([AnswerId] ASC)
)";
Run Code Online (Sandbox Code Playgroud)
以下是我尝试过的结果:
这适用于一个孩子:
var a = new Answer{
Text = "AA",
QuestionId = 14
};
question.Answers.Add(a);
_uow.Questions.Update(question);
_uow.Commit();
Run Code Online (Sandbox Code Playgroud)
这不适用于多个孩子:
错误:ObjectStateManager中已存在具有相同键的对象.ObjectStateManager无法使用相同的键跟踪多个对象.
var a = new Answer{
AnswerId = 0,
Text = "AAA",
QuestionId = 14
};
var b = new Answer {
AnswerId = 0,
Text = "BBB",
QuestionId = 14
};
question.Answers.Add(a);
question.Answers.Add(b);
_uow.Questions.Update(question);
_uow.Commit();
Run Code Online (Sandbox Code Playgroud)
这不适用于多个孩子:
它创建了AnswerID的1000和1001,但我希望数据库创建新的Id.
var a = new Answer{
AnswerId = 1000,
Text = "AAA",
QuestionId = 14
};
var b = new Answer {
AnswerId = 1001,
Text = "BBB",
QuestionId = 14
};
question.Answers.Add(a);
question.Answers.Add(b);
_uow.Questions.Update(question);
_uow.Commit();
Run Code Online (Sandbox Code Playgroud)
不起作用:
编译错误.无法将null转换为int
var a = new Answer{
AnswerId = null,
Text = "AAA",
QuestionId = 14
};
var b = new Answer
{
AnswerId = null,
Text = "BBB",
QuestionId = 14
};
question.Answers.Add(a);
question.Answers.Add(b);
_uow.Questions.Update(question);
_uow.Commit();
Run Code Online (Sandbox Code Playgroud)
不起作用:
ObjectStateManager无法使用相同的键跟踪多个对象.
var a = new Answer{
Text = "AAA",
QuestionId = 14
};
var b = new Answer
{
Text = "BBB",
QuestionId = 14
};
question.Answers.Add(a);
question.Answers.Add(b);
_uow.Questions.Update(question);
_uow.Commit();
Run Code Online (Sandbox Code Playgroud)
在我的应用程序中,我在客户端上生成了一个或多个新的Answer对象,然后将这些对象发送到服务器.上面我模拟了如果不将客户端添加到问题中会发生什么.请注意,将所有Answers添加到Question对象是在客户端上完成的,然后以JSON字符串形式提供给服务器.然后将其反序列化为这样的问题对象:
public HttpResponseMessage PutQuestion(int id, Question question) {
_uow.Questions.Update(question);
_uow.Commit();
Run Code Online (Sandbox Code Playgroud)
我想要使用a创建每个Answer对象new identity ID,以便将这些对象添加到Question对象中,并以正常方式返回Question对象.
我不知道如何做到这一点.到目前为止我所有的简单测试都不起作用.请注意,这是我们小组成员先前提出的问题的变体,该问题不太明确,我试图关闭.这个问题我希望更清楚.
笔记:
以下是更新编码的方式:
public virtual void Update(T entity)
{
DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
if (dbEntityEntry.State == EntityState.Detached)
{
DbSet.Attach(entity);
}
dbEntityEntry.State = EntityState.Modified;
}
Run Code Online (Sandbox Code Playgroud)
我也遇到了同样的身份"限制".事实证明,如果您添加父项和任何子项,EF可以处理父项和子项都被添加到一起的事实.更新父项并同时插入两个子项时遇到问题.如果您附加父母,EF将自动接收这两个孩子并附加他们,无论您是否愿意.由于我们希望它自动生成Id,因此我们不会设置子项的主键.但是,当父级是更新时,EF无法处理具有相同主键的项目,并且由于两个子级都具有相同的PK 0,因此EF不会爆炸.
我找到的唯一方法是手动将子项的ID设置为不同的数字.我通常将第一个孩子的Id设置为-1,然后将-2设置为第二个孩子,依此类推.这将导致EF保存子项,并且由于在数据库上运行标识,密钥将自动更新,因为-1和-2不是有效的标识值.
但是,如果您达到第3级或更高级别,这将导致巨大的痛苦.您不仅需要为每个孩子更新此PK,而且还必须将其任何子级上的FK更新为此新的-1或-2值.否则,保存将再次失败!
我看到的唯一其他选项实际上只是一次插入一个子节点并调用save,因此上下文不处理具有相同PK的多个对象,但这种情况违背了ORM的目的...
你有没有提到你要添加a两次......?!
question.Answers.Add(a);
question.Answers.Add(a);
Run Code Online (Sandbox Code Playgroud)
通常,要添加 id 为标识的项目,必须跳过设置 id。您还应该将[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]属性添加到这些 ID:
public class Answer
{
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int AnswerId { get; set; }
public string Text { get; set; }
public int QuestionId { get; set; }
public virtual Question Question { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
并添加这样的数据:
var a = new Answer{
Text = "AAA",
QuestionId = 14
};
var b = new Answer
{
Text = "BBB",
QuestionId = 14
};
dbContext.Answers.Add(a);
dbContext.Answers.Add(b);
dbContext.SaveChanges();
// ...
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
13326 次 |
| 最近记录: |