多个自引用导航属性
Multiple self-referencing naviation properties
我们销售一种产品,我们为其颁发许可证号并且客户可以每年升级一次。我想设置一个 License
POCO,它通过定义 UpgradedTo
和 UpgradedFrom
导航属性来跟踪此升级信息,这将使我们能够轻松地移动 up/down "chain" 的相关许可证。所以基本上是这样的:
public class License
{
[Key]
public string LicenseNum { get; set; }
// Other properties relating to license omitted...
// Optional relationship.
public License UpgradedTo { get; set; }
// Optional relationship.
public License UpgradedFrom { get; set; }
}
我真的很困惑如何使用 EF 注释和 Fluent API 来定义它。我认为自我参照方面让我感到困惑。
我们还希望能够在给定 License
上设置这些 UpgradeTo
/UpgradeFrom
属性中的任何一个,并让 EF 处理 "opposite" 在关系的另一端升级属性。所以像下面这样:
// Licenses upgraded 1 > 2 > 3
License lic1 = CreateLicense('1');
License lic2 = CreateLicense('2');
License lic3 = CreateLicense('3');
using (var db = new Model1())
{
// Insert into database
db.Licenses.Add(lic1);
db.Licenses.Add(lic2);
db.Licenses.Add(lic3);
db.SaveChanges();
// Specify UpgradeFrom/UpgradeTo info only on lic2.
lic2.UpgradedFrom = lic1;
lic2.UpgradedTo = lic3;
db.SaveChanges();
// lic1 and lic3 automatically update possible?
Debug.Assert(lic1.UpgradedTo == lic2);
Debug.Assert(lic3.UpgradedFrom == lic2);
}
这种情况非常棘手,因为依赖性是如何工作的。
诀窍是添加一个或多个额外的 "fake" 属性来完成这项工作。
如果您设置 UpgradeTo 值,此 class 将自动设置 UpgradedFrom 属性。
示例:
using (var ctx = new TestContext2())
{
var license1 = ctx.Licenses.Add(new License() { LicenseNum = "1.0.0"});
ctx.SaveChanges();
var license2 = license1.UpgradeTo = new License() { LicenseNum = "1.0.2"};
ctx.SaveChanges();
var license3 = license2.UpgradeTo = new License() { LicenseNum = "1.0.3" };
ctx.SaveChanges();
}
实体
public class License
{
[Key]
public string LicenseNum { get; set; }
private License _upgradeTo;
private License _upgradedFrom;
public License UpgradeTo
{
get { return _upgradeTo; }
set
{
_upgradeTo = value;
if (_upgradeTo != null && _upgradeTo.UpgradedFrom != this)
{
_upgradeTo.UpgradedFrom = this;
}
}
}
public License UpgradedFrom
{
get { return _upgradedFrom; }
set
{
_upgradedFrom = value;
if (_upgradedFrom != null && _upgradedFrom.UpgradeTo != this)
{
_upgradedFrom.UpgradeTo = this;
}
}
}
internal License InternalUpgradedTo
{
get { return UpgradeTo; }
}
internal License InternalUpgradedFrom
{
get { return UpgradedFrom; }
}
}
上下文
public class TestContext2 : DbContext
{
public TestContext2() : base(My.Config.ConnectionStrings.TestDatabase)
{
}
public DbSet<License> Licenses { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<License>()
.HasOptional(v => v.UpgradeTo)
.WithOptionalDependent(x => x.InternalUpgradedFrom);
modelBuilder.Entity<License>()
.HasOptional(v => v.UpgradedFrom)
.WithOptionalDependent(x => x.InternalUpgradedTo);
}
}
我们销售一种产品,我们为其颁发许可证号并且客户可以每年升级一次。我想设置一个 License
POCO,它通过定义 UpgradedTo
和 UpgradedFrom
导航属性来跟踪此升级信息,这将使我们能够轻松地移动 up/down "chain" 的相关许可证。所以基本上是这样的:
public class License
{
[Key]
public string LicenseNum { get; set; }
// Other properties relating to license omitted...
// Optional relationship.
public License UpgradedTo { get; set; }
// Optional relationship.
public License UpgradedFrom { get; set; }
}
我真的很困惑如何使用 EF 注释和 Fluent API 来定义它。我认为自我参照方面让我感到困惑。
我们还希望能够在给定 License
上设置这些 UpgradeTo
/UpgradeFrom
属性中的任何一个,并让 EF 处理 "opposite" 在关系的另一端升级属性。所以像下面这样:
// Licenses upgraded 1 > 2 > 3
License lic1 = CreateLicense('1');
License lic2 = CreateLicense('2');
License lic3 = CreateLicense('3');
using (var db = new Model1())
{
// Insert into database
db.Licenses.Add(lic1);
db.Licenses.Add(lic2);
db.Licenses.Add(lic3);
db.SaveChanges();
// Specify UpgradeFrom/UpgradeTo info only on lic2.
lic2.UpgradedFrom = lic1;
lic2.UpgradedTo = lic3;
db.SaveChanges();
// lic1 and lic3 automatically update possible?
Debug.Assert(lic1.UpgradedTo == lic2);
Debug.Assert(lic3.UpgradedFrom == lic2);
}
这种情况非常棘手,因为依赖性是如何工作的。
诀窍是添加一个或多个额外的 "fake" 属性来完成这项工作。
如果您设置 UpgradeTo 值,此 class 将自动设置 UpgradedFrom 属性。
示例:
using (var ctx = new TestContext2())
{
var license1 = ctx.Licenses.Add(new License() { LicenseNum = "1.0.0"});
ctx.SaveChanges();
var license2 = license1.UpgradeTo = new License() { LicenseNum = "1.0.2"};
ctx.SaveChanges();
var license3 = license2.UpgradeTo = new License() { LicenseNum = "1.0.3" };
ctx.SaveChanges();
}
实体
public class License
{
[Key]
public string LicenseNum { get; set; }
private License _upgradeTo;
private License _upgradedFrom;
public License UpgradeTo
{
get { return _upgradeTo; }
set
{
_upgradeTo = value;
if (_upgradeTo != null && _upgradeTo.UpgradedFrom != this)
{
_upgradeTo.UpgradedFrom = this;
}
}
}
public License UpgradedFrom
{
get { return _upgradedFrom; }
set
{
_upgradedFrom = value;
if (_upgradedFrom != null && _upgradedFrom.UpgradeTo != this)
{
_upgradedFrom.UpgradeTo = this;
}
}
}
internal License InternalUpgradedTo
{
get { return UpgradeTo; }
}
internal License InternalUpgradedFrom
{
get { return UpgradedFrom; }
}
}
上下文
public class TestContext2 : DbContext
{
public TestContext2() : base(My.Config.ConnectionStrings.TestDatabase)
{
}
public DbSet<License> Licenses { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<License>()
.HasOptional(v => v.UpgradeTo)
.WithOptionalDependent(x => x.InternalUpgradedFrom);
modelBuilder.Entity<License>()
.HasOptional(v => v.UpgradedFrom)
.WithOptionalDependent(x => x.InternalUpgradedTo);
}
}