在以前版本的EF中,我可以使用以下代码来实现识别关系:
public class Child
{
[Key, Column(Order = 1)]
public virtual int Id { get; set; }
[Key, Column(Order = 2)]
public virtual int ParentId { get; set; }
public virtual Parent Parent { get; set; }
}
需要从这样的集合中轻松删除一个孩子:
var parent = _context.Parents.First();
var child = parent.Children.First();
parent.Children.Remove(child);
_context.SaveChanges();
http://www.kianryan.co.uk/2013/03/orphaned-child/(方法#2)中描述了这种方法。
但在EF7中,此代码在创建迁移时抛出异常:
执行解析操作时抛出异常。见 InnerException以获取详细信息。 --->实体类型'Child'具有复合 使用数据注释定义的主键。设置复合主要 密钥,使用流畅的API。
我还尝试按照How to define nested Identifying Relationships Entity Framework code first中的说明在以下代码中使用FluentAPI:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Parent>()
.HasMany(p => p.Children)
.WithOne(c => c.Parent);
modelBuilder.Entity<Child>()
.HasKey(c => new {c.Id, c.ParentId});
base.OnModelCreating(modelBuilder);
}
此方法允许成功生成迁移,但是当我尝试从Children
集合中删除子项时,我遇到以下异常:
System.InvalidOperationException:实体类型之间的关联 '父母'和'孩子'已被切断,但外键是这个 关系不能设置为null。如果依赖实体应该是 删除,然后设置关系以使用级联删除。
但我不想使用级联删除,我想使用识别关系!
请帮助我理解我做错了什么。谢谢!
答案 0 :(得分:2)
在删除时使用级联,因为这是它用于:
modelBuilder.Entity<Parent>()
.HasMany(p => p.Children)
.WithOne(c => c.Parent);
.WillCascadeOnDelete(true);
答案 1 :(得分:0)
以防万一有人看到此错误,让我告诉您我如何解决我的问题:
进行更新时,在EF上,您首先需要查询数据库并获取数据模型,然后将更改后的域层模型映射到数据库上(基本上将字段复制到数据上),最后调用DBContext更新方法,然后保存更改。
我的问题是我的模型(不是数据模型,域模型)上也有子对象。
这是数据层模型(例如):
public class Parent
{
public int ChildId {get; set; }
[ForeignKey("ChildId")]
public virtual Child Child { get; set; }
}
这是域层模型应为的方式:
public class Parent
{
public int ChildId { get; set; }
//public Child Child { get; set; } // this caused the error, keep reading if you want to know more.
}
当我看到错误时,我一直在使用Autofac的运行时映射器将域层模型的属性映射到数据层模型上。但是,域层模型中的子级为null,因此它将使数据层无效,从而导致错误:
“实体类型'Parent'和'Child'之间的关联已被切断,但是该关系的外键不能设置为null。如果应该删除从属实体,则设置该关系以使用级联删除。”
在数据库上下文类中,我定义了以下关系:
modelBuilder.Entity<Parent>()
.HasOne(a => a.Child)
.WithMany()
.HasForeignKey(p => p.ChildId)
.OnDelete(DeleteBehavior.Restrict);
正在工作。