我正在尝试将我的第一个EF代码首先创建到数据库中。不幸的是,当我试图将我的对象保存到DB时,我得到了这个例外:
无法确定相关操作的有效排序。 由于外键约束,模型可能存在依赖关系 要求或商店生成的值。
以下是我用来填充数据库的代码:
using (var context = new MySample.Context())
{
context.Database.CreateIfNotExists();
CloudFile f = new CloudFile(, "file1");
CloudDirectory d = new CloudDirectory(CloudObject.CloudContentType.Customer, "directory1");
d.Nodes.Add(d);
FileGroup g = new FileGroup();
g.CloudObjects.Add(d);
context.FileGroups.Add(g);
context.SaveChanges();
}
实际上我想创建一个FileGroup
类型的对象。该对象包含文件(CloudFile
)或目录(CloudDirectory
)。目录可以包含其他目录或文件。
以下是上述对象的类:
public class FileGroup {
public FileGroup()
{
CloudObjects = new HashSet<CloudObject>();
}
public int FileGroupId { get; set; }
public string Name { get; set; }
public virtual ICollection<CloudObject> CloudObjects { get; set; }
}
public abstract class CloudObject {
public CloudObject(string name)
{
Name = name;
}
public int CloudObjectId { get; set; }
public string Name { get; set; }
public abstract bool hasChildren { get; }
public int? ParentId { get; set; }
public virtual Node Parent { get; set; }
public int? FileGroupId { get; set; }
public virtual FileGroup FileGroup { get; set; }
}
public class CloudDirectory : CloudObject {
public CloudDirectory(string name) :base(name)
{
Nodes = new HashSet<CloudObject>();
}
public override bool hasChildren
{
get
{
return Nodes.Any();
}
}
public virtual ICollection<CloudObject> Nodes { get; set; }
}
public class CloudFile : CloudObject {
public CloudFile(string name) : base(name)
{
}
public string ETag { get; set; }
public override bool hasChildren
{
get
{
return false;
}
}
}
知道我需要在我的对象中进行哪些更改才能成功存储它们吗?
答案 0 :(得分:1)
测试代码中的一些更改(代码注释解释了它们):
using (var context = new MySample.Context())
{
context.Database.CreateIfNotExists();
CloudFile f = new CloudFile("file1");
CloudDirectory d = new CloudDirectory("directory1");
//This seems to be wrong:
//d.Nodes.Add(d);
d.Nodes.Add(f); //I guess you don't want d to be its own parent, but want it to be f's parent
FileGroup g = new FileGroup();
g.CloudObjects.Add(d);
//Another way to do it:
//d.FileGroup = g;
//You also want f to be in the FileGroup, you have to add it explicitly
g.CloudObjects.Add(f);
//Another way to do it:
//f.FileGroup = g;
context.FileGroups.Add(g);
context.SaveChanges();
}
由于实体之间的关系对于处理它们的EF自动约定而言有点过于复杂,您应该在DbContext
中为它们添加显式映射:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
...
modelBuilder.Entity<CloudObject>().HasOptional(x => x.Parent).WithMany(x => x.Nodes).HasForeignKey(x => x.ParentId);
modelBuilder.Entity<CloudObject>().HasOptional(x => x.FileGroup).WithMany(x => x.CloudObjects).HasForeignKey(x => x.FileGroupId);
}
注意:我在此假设FileGroup
对于给定的CloudObject
不是必需的。如果是强制性的,您应该将方法HasOptional
更改为HasRequired
。
您还应该更改此属性的类型:
public abstract class CloudObject
{
...
//public virtual Node Parent { get; set; }
public virtual CloudDirectory Parent { get; set; }
...
}
您的迁移必须看起来像这样:
CreateTable(
"dbo.CloudObjects",
c => new
{
CloudObjectId = c.Int(nullable: false, identity: true),
Name = c.String(),
ParentId = c.Int(),
FileGroupId = c.Int(),
ETag = c.String(),
Discriminator = c.String(nullable: false, maxLength: 128),
})
.PrimaryKey(t => t.CloudObjectId)
.ForeignKey("dbo.FileGroups", t => t.FileGroupId)
.ForeignKey("dbo.CloudObjects", t => t.ParentId)
.Index(t => t.ParentId)
.Index(t => t.FileGroupId);
CreateTable(
"dbo.FileGroups",
c => new
{
FileGroupId = c.Int(nullable: false, identity: true),
Name = c.String(),
})
.PrimaryKey(t => t.FileGroupId);