【问题标题】:Good way to do "either/or" relationship in Entity Framework (SQL Server)在实体框架(SQL Server)中做“非此即彼”关系的好方法
【发布时间】:2011-05-11 18:22:35
【问题描述】:

假设我有两个实体对象“table”和“chicken”。

现在假设我有一个“机翼”对象,我希望该机翼与桌子和鸡的关系为 0..1-1。换句话说,我想要一个可以为空的 table.wing 和一个可以为空的 chicken.wing。

有没有一种好方法,使用 Entity Framework 4,使翅膀对象具有可以与桌子或鸡相关联的限制?

注意:我不想在我的字典中有一个有翼对象的基类——这需要是“有一个”而不是“是一个”。

我的想法是我不能对引用的集合进行唯一的限制,所以我必须用类似的东西来包装实体属性:

public partial class Wing:
...
  public Table Table
    {
      get { return this.Table; }
      set { 
          //make sure Chicken is null
          this.Table = value;
          }
    }
...
}

这让我觉得很老套而且不太干净,所以我一直在寻找更好的(如果不是最好的)实践解决方案。

编辑:

需要明确的是,我目前在 table 和 Wing 之间有 0..1-1 的关系,在 chicken 和 Wing 之间有 0..1-1 的关系。因此,我可以创建一个 table.wing,然后我可以查看wing.table。我想要的是确保我在查询 table.wing.chicken 或 chicken.wing.table 时总是有一个空值。翼必须与一张桌子或一个翼相关联。

当前行为示例:

回应@morganppdx 的评论:

鉴于此实体图:

Program.cs 中有以下内容:

class Program
{  
 static void Main(string[] args)
    {
        Model1Container container = new Model1Container();

        Wing chickenwing = new Wing { Shape = "birdlike" };
        Chicken chicken1 = new Chicken { Breed = "Andalusian", Wing = chickenwing };
        Table table1 = new Table { Style = "Mission", Wing = chickenwing }; // Should throw exception!
        container.AddToChickens(chicken1);
        container.AddToTables(table1);
        container.SaveChanges();

        Console.Write(String.Format("Table {0}'s wing has a {1} shape...", table1.Id, table1.Wing.Shape));
        Console.Write(String.Format("Table {0} has {1} chicken wings!", table1.Id, table1.Wing.Chicken.Breed));
        Console.ReadLine(); //wait for input to give us time to read
    }
}

结果控制台将显示:

Table 1's wing has a birdlike shape...Table 1 has Andalusian chicken wings!

这个结果是我希望避免的。当 chickenwing 与 table1 关联时,它应该抛出异常,因为它已经与 chicken1 关联,并且不能同时与 table 和鸡关联。

很可能我建立的关系不正确,因此没有在我想要的地方得到@morganpdx 声明的异常。

代码在:https://github.com/mettadore/WingThing

【问题讨论】:

  • 您的 Table 和 Chicken 对象应该与 Wing 对象有关联。父对象 Table 和 Chicken 具有对 Wing 对象的引用这一事实是否足以限制这种关系?我的意思是,如果您尝试引用 Car.Wing...或者我不理解正在解决的问题?
  • 当然,这会创建两个不同的 Wing 对象……一个 Table.Wing 和一个 Chicken.Wing。小时。
  • 回复:你的编辑:你能做到吗?查询table.wing.chicken?如果你这样做,它应该抛出一个异常,我认为?我想我的意思是我不确定你需要强制执行该限制; EF 将为您强制执行!耶~!

标签: sql entity-framework-4 one-to-one chicken-scheme


【解决方案1】:

在我的脑海中,我的建议是创建扩展 Wing 对象的子对象,并使用这些子对象代替您的 Wing 对象:

public class ChickenWing : Wing
{
  public Table Table { get { throw new NoTablesAllowedException; }}
}

public class TableWing: Wing
{
  public Chicken Chicken { get { throw new NoChickensHereException; }}
}

您发布的代码将如下所示:

class Program
{          
    static void Main(string[] args)           
    {               
        Model1Container container = new Model1Container();                      
        ChickenWing chickenwing = new ChickenWing { Shape = "birdlike" };
        TableWing tablewing = new TableWing { Shape = "circular" };
        Chicken chicken1 = new Chicken { Breed = "Andalusian", Wing = chickenwing };               
        Table table1 = new Table { Style = "Mission", Wing = tablewing };             
        container.AddToChickens(chicken1);               
        container.AddToTables(table1);               
        container.SaveChanges();                      

        Console.Write(String.Format("Table {0}'s wing has a {1} shape...", table1.Id, table1.Wing.Shape));               
        Console.Write(String.Format("Table {0} has {1} chicken wings!", table1.Id, table1.Wing.Chicken.Breed));               
        Console.ReadLine(); //wait for input to give us time to read           
    }       
} 

到目前为止,我还没有做过类似的事情,但我相信这应该可行。本质上,Wing 对象充当描述 ChickenWing 和 TableWing 对象的接口,但这些对象是用于谨慎目的的谨慎对象。

【讨论】:

  • 啊,另一边的子类。根本没想过!这就是我爱你的原因,@morganpdx!
【解决方案2】:

查看您的模型,我认为您可以简单地将 Table 和 Wing Ids 设置为 IDENTITY,具有不同的种子和增量 2 - 一个只有偶数,第二个只有奇数 Id,在这种情况下,永远不会有与两个都。

关键是 EF 中的一对一关系始终建立在主键上,因此wing 必须具有 table 或 chicken 的主键,并且在定义独占序列时,wing 永远不会同时拥有 table 和 chicken。

【讨论】:

  • 有趣的想法,但是如果我添加另一个类,我需要更改它以确保我的基于 ID 的唯一性系统继续有效。似乎它适用于两个对象的特殊情况,但不适用于 n 个对象的一般情况。
  • 是的,但是假设您的场景已经是一个非常特殊的情况。
猜你喜欢
  • 1970-01-01
  • 2015-07-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多