我正在与ef一起在.net核心项目中工作。 我有两个桌子:
public class Asset
{
[Key]
public Guid Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
// Relationships
public ICollection<AssetMixRecord> AssetMixRecords { get; set; }
}
public class AssetMixRecord
{
public decimal Percentage { get; set; }
public Guid AssetId { get; set; }
// Relationships
public Guid ParentAssetId { get; set; }
}
上下文如下:
modelBuilder.Entity<Asset>()
.HasMany(a => a.AssetMixRecords)
.WithOne()
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<AssetMixRecord>()
.HasKey(c => new { c.ParentAssetId, c.AssetId })
.IsClustered();
此迁移代码如下:
migrationBuilder.CreateTable(
name: "AssetMixRecords",
columns: table => new
{
AssetId = table.Column<Guid>(nullable: false),
ParentAssetId = table.Column<Guid>(nullable: false),
Percentage = table.Column<decimal>(type: "decimal(8,7)", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AssetMixRecords", x => new { x.ParentAssetId, x.AssetId })
.Annotation("SqlServer:Clustered", true);
table.ForeignKey(
name: "FK_AssetMixRecords_Assets_AssetId",
column: x => x.AssetId,
principalTable: "Assets",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
这一切都很好,没错。但是“ ParentAssetId”也是“ Assets.Id”的外键。
我们的用例如下:
var asset1 = new Asset();
var asset2 = new Asset();
dbContext.Add(asset1);
dbContext.Add(asset2);
dbContext.SaveChanges();
var asset3 = new Asset();
asset3.AssetMixRecords.Add(new AssetMixRecord()
{
AssetId = asset1.Id,
ParentAssetId = asset3.Id
});
asset3.AssetMixRecords.Add(new AssetMixRecord()
{
AssetId = asset2.Id,
ParentAssetId = asset3.Id
});
dbContext.Add(asset3);
dbContext.SaveChanges();
我无法将第二个外键添加到迁移代码中。我应该手动添加它吗?
感谢和问候
S。
答案 0 :(得分:0)
请查看我的解决方案以及完整的演示,它将产生以下迁移。我不确定是否可以将DeleteBehavior.Cascade
用于这种架构,EF迁移工具抱怨循环依赖。
migrationBuilder.DropForeignKey(
name: "FK_AssetMixRecords_Assets_AssetId",
table: "AssetMixRecords");
migrationBuilder.AddForeignKey(
name: "FK_AssetMixRecords_Assets_AssetId",
table: "AssetMixRecords",
column: "AssetId",
principalTable: "Assets",
principalColumn: "Id");
migrationBuilder.AddForeignKey(
name: "FK_AssetMixRecords_Assets_ParentAssetId",
table: "AssetMixRecords",
column: "ParentAssetId",
principalTable: "Assets",
principalColumn: "Id");
演示本身在下面。请注意,Asset
中有2个导航属性。 EF会根据其位置(AssetId或ParentAssetId)在其中加载子实体
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
namespace ConsoleApp9
{
public class Asset
{
[Key]
public Guid Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
// items where AssetMixRecord.AssetId == Id
public ICollection<AssetMixRecord> AssetMixRecords { get; set; }
// items where AssetMixRecord.ParentAssetId == Id
public ICollection<AssetMixRecord> ParentAssetMixRecords { get; set; }
}
public class AssetMixRecord
{
public decimal Percentage { get; set; }
public Guid AssetId { get; set; }
public virtual Asset Asset { get; set; }
public Guid ParentAssetId { get; set; }
public virtual Asset ParentAsset { get; set; }
}
public class ApplicationDbContext : DbContext
{
public DbSet<Asset> Assets { get; set; }
public DbSet<AssetMixRecord> AssetMixRecords { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Server=DESKTOP-1111111;Database=testef11db;Integrated Security=true;");
base.OnConfiguring(optionsBuilder);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Asset>()
.HasMany(a => a.AssetMixRecords)
.WithOne(x => x.Asset)
.HasForeignKey(x => x.AssetId)
.OnDelete(DeleteBehavior.NoAction);
modelBuilder.Entity<Asset>()
.HasMany(x => x.ParentAssetMixRecords)
.WithOne(x => x.ParentAsset)
.HasForeignKey(x => x.ParentAssetId)
.OnDelete(DeleteBehavior.NoAction);
modelBuilder.Entity<AssetMixRecord>()
.HasKey(c => new { c.ParentAssetId, c.AssetId })
.IsClustered();
base.OnModelCreating(modelBuilder);
}
}
class Program
{
static void Main(string[] args)
{
var dbContext = new ApplicationDbContext();
var asset1 = new Asset();
var asset2 = new Asset();
dbContext.Add(asset1);
dbContext.Add(asset2);
dbContext.SaveChanges();
var assetDataMixRecord = new AssetMixRecord()
{
AssetId = asset1.Id,
ParentAssetId = asset2.Id
};
dbContext.Add(assetDataMixRecord);
dbContext.SaveChanges();
var assets = dbContext.Assets
.Include(x => x.AssetMixRecords)
.Include(x => x.ParentAssetMixRecords)
.ToList();
}
}
}
如果您不希望ParentAssetId
等于ChildAssetId
,只需在下面的解决方案中添加以下代码
modelBuilder.Entity<AssetMixRecord>()
.HasCheckConstraint("PK_Check_ChildAssetId_And_ParentAssetId", "ParentAssetId != ChildAssetId");
如果您将AssetMixRecords
的{{1}}更改为ParentAssetMixRecords
,您的用例就可以正常工作
asset3