Хороший способ сделать отношения «или / или» в Entity Framework (SQL Server) - PullRequest
4 голосов
/ 11 мая 2011

Допустим, у меня есть два объекта сущности "таблица" и "курица".

Теперь, допустим, у меня есть объект "крыло", и я хочу, чтобы это крыло имело отношение 0..1-1 со столом и курицей. Другими словами, я хочу, чтобы nullable table.wing и nullable chicken.wing.

Есть ли хороший способ, используя Entity Framework 4, заставить объект крыла иметь ограничение на то, что он может быть связан с таблицей ИЛИ с курицей?

Примечание: я не хочу, чтобы в моем словаре был базовый класс крылатых объектов - это должно быть "имеет один", а не "есть один".

Я думаю, что я не могу установить уникальную ограниченность для коллекции ссылок, поэтому мне придется обернуть свойства Entity чем-то вроде:

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

Это кажется мне довольно хакерским и не слишком чистым, поэтому я искал лучшее, если не лучшее, решение для практики.

Edit:

Для ясности, в настоящее время у меня есть отношение 0..1-1 между столом и крылом и соотношение 0..1-1 между курицей и крылом. Таким образом, я могу создать table.wing и посмотреть на wing.table. Я хочу убедиться, что у меня ВСЕГДА есть нулевое значение, если я запрашиваю table.wing.chicken или chicken.wing.table. Крыло должно быть связано с ЛИБО одним столом ИЛИ одним крылом.

Пример текущего поведения:

В ответ на комментарий @ morganppdx:

С учетом этой диаграммы сущностей:

enter image description here

И следующее в 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!

Этого результата я хочу избежать. Он должен выдавать исключение, когда цыплёнок связан с таблицей1, поскольку он уже связан с курицей1 и не может быть связан как с таблицей, так и с курицей.

Вполне возможно, что я строю отношения неправильно, и, таким образом, не получаю заявленное исключение @ morganpdx там, где я этого хочу.

Код доступен по адресу: https://github.com/mettadore/WingThing

Ответы [ 2 ]

1 голос
/ 12 мая 2011

Вне моей головы, я бы предложил создать дочерние объекты, которые расширяют объект 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, но это дискретные объекты, используемые в скрытых целях.

0 голосов
/ 12 мая 2011

Глядя на вашу модель, я думаю, вы можете просто сделать Table и Wing Id в качестве IDENTITY с различным начальным числом и приращением 2 - один будет иметь только четные, а второй только нечетные Id, и в этом случае никогда не будет крыла, которое будет связано с и то и другое.

Дело в том, что отношение один-к-одному в EF всегда строится на первичных ключах, поэтому у wing должен быть первичный ключ таблицы или цыпленка, и при определении исключительных последовательностей никогда не случится, что у крыла могут быть оба стола - цыпленок.

...