【问题标题】:Multiple self-referencing naviation properties多个自参考导航属性
【发布时间】:2016-07-03 20:32:21
【问题描述】:

我们销售一种产品,我们为其颁发许可证编号,并且客户可以每年升级。我想设置一个License POCO,通过定义UpgradedToUpgradedFrom 导航属性来跟踪此升级信息,这将使我们能够轻松地向上/向下移动相关许可证的“链”。所以基本上是这样的:

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 Annotations 和 Fluent API 来定义它。我认为自我参照方面是让我绊倒的地方。

我们还希望能够在给定 License 上设置这些 UpgradeTo/UpgradeFrom 属性之一,并让 EF 处理关系另一端的“相反”升级属性.所以类似于以下内容:

// 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);
}

【问题讨论】:

    标签: c# entity-framework code-first self-reference


    【解决方案1】:

    这种情况非常棘手,因为依赖是如何工作的。

    诀窍是添加一个或多个额外的“假”属性来完成这项工作。

    如果您设置 UpgradeTo 值,此类将自动设置 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);
        }
    }
    

    【讨论】:

    • 这种方法非常有效。非常感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-23
    相关资源
    最近更新 更多