2013-08-12 3 views
4

Если у объекта есть несколько отношений, и я пытаюсь вставить одновременно данные на них, EF вызывает InvalidCastException.InvalidCastException: EF сбой при вставке объекта с несколькими отношениями

В качестве примера, представьте себе, эти классы домена:

public class Person : Entity<Guid> 
{ 
    public string Name { get; set; } 
    public ICollection<Watch> Watches { get; set; } 
    public ICollection<Shoe> Shoes { get; set; } 
} 

public class Shoe : Entity<Guid> 
{ 
    public string Brand { get; set; } 
} 

public class Watch : Entity<Guid> 
{ 
    public string Brand { get; set; } 
} 

Пример использования # 1 (отлично работает):

using (var context = new MultipleRelationshipsContext()) 
{ 
    var watches = 
     new List<Watch>() { 
      new Watch { Brand = "Rolex" } 
     }; 

    context.Set<Person>().Add(
     new Person 
     { 
      Name = "Warren Buffett", 
      Watches = watches 
     } 
    ); 
} 

Используйте случай # 2 (отлично работает тоже):

using (var context = new MultipleRelationshipsContext()) 
{ 
    var shoes = 
     new List<Shoe>() { 
      new Shoe { Brand = "Cole Haan" } 
     }; 

    context.Set<Person>().Add(
     new Person 
     { 
      Name = "Barack Obama", 
      Shoes = shoes 
     } 
    ); 
} 

Вариант использования № 3 (InvalidCastException):

using (var context = new MultipleRelationshipsContext()) 
{ 
    var watches = 
     new List<Watch>() { 
      new Watch { Brand = "Casio" } 
     }; 

    var shoes = 
     new List<Shoe>() { 
      new Shoe { Brand = "New Balance" } 
     }; 

    context.Set<Person>().Add(
     new Person 
     { 
      Name = "Steve Jobs", 
      Watches = watches, 
      Shoes = shoes 
     } 
    ); 
} 

В третьем случае выбрано InvalidCastException, в котором говорится, что EF не может отличить от 'EntityFrameworkMultipleRelationships.Entities.Watch до' EntityFrameworkMultipleRelationships.Entities.Shoe '.

Я новичок в EF, но я думаю, что здесь происходит нечто неправильное.

Я бы приложил любые намеки, чтобы указать на возможное решение!

PD .: Чтобы проверить себя как можно быстрее, загрузите это решение VS2012: https://dl.dropboxusercontent.com/u/22887057/EntityFrameworkMultipleRelationships.zip. Следуйте за README.txt, чтобы создать базу данных по шаблону кода.

UPDATE

Как @ Крис отметил, что проблема в том, что EF считает обуви и смотреть объекты являются одинаковыми. Это было вызвано плохим реализованным избытком Equals. Это на самом деле является источником проблем:

public abstract class Entity<T> 
{ 
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] 
    [Column("Id")] 
    public T Id { get; set; } 

    public override bool Equals(object obj) 
    { 
     Entity<T> entityOfT = obj as Entity<T>; 
     if (entityOfT == null) 
      return false; 

     return object.Equals(this.Id, entityOfT.Id); 
    } 

    public override int GetHashCode() 
    { 
     return this.Id.GetHashCode(); 
    } 
} 

Если два различных типа сущностей (как Watch и Shoe) имеют один и тот же Id, EF рассматривает их равными.

Добавление проверки времени выполнения для переопределения Equals учитывает тип объекта и поэтому решает эту проблему.

... 
return this.GetType() == entityOfT.GetType() && object.Equals(this.Id, entityOfT.Id); 
... 
+0

делает эту работу context.Set () .Add ( новый Person { Name = "Стив Джобс", часы = часы } ); – Ehsan

+1

Конечно, это тот же случай, что и # 1. –

+0

У вас это исправлено? Я столкнулся с подобной проблемой, только она дает ошибку, когда у меня есть таблица, разделенная на два класса (сущности домена), и ошибка говорит, что она не может отбрасывать один на другой. http://stackoverflow.com/questions/19391238/how-to-save-an-object-graph-with-entityframework-lazy-load-disabled-proxy-disa –

ответ

1

Я не уверен в Entity Framework внутренностей (хотя я мог бы попробовать и посмотреть после этого), но я думаю, что вы проблема является возможным сочетанием двух вещей:

1) То, как Entity Framework автоматически генерирует наборы, которые хранят ваши объекты.

2) У вас есть два дочерних объекта с одним и тем же Гидом, который вернет Equals(..) true, хотя они имеют разный тип.

Ваш код будет работать, если вы либо:

Определить либо Shoe/Watch (или оба), и добавить его/их к соответствующему набору (ы):

context.Set<Shoe>().Add(aShoe); 

или определить другое значение для Guid для Watch или Shoe

Watch tWatch = new Watch { Brand = "Casio", Id = new System.Guid("00000000-0000-0000-0000-000000000001") }; 

Если вы не сделаете ни тех, и вы будете следовать вашей третьей экс достаточно, вы можете следить за отладчиком и находить, что вы достигнете точки, где Equals вызывается с Watch и Shoe, и результат верен - я предполагаю, что это тот момент, когда Entity Framework выбрасывает ваше исключение.

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

1

Не уверен, почему отбрасывается, что конкретная ошибка, но EF, кажется, путаясь в связи с вашим определением Entity.Id. Если вы переместите поле PK в определения классов обуви и часов, оно будет работать. Кроме того, если вы добавляете объекты часов и обуви к их соответствующим наборам DbContext перед их добавлением через коллекции к объекту Person, он также работает. В любом случае, будучи немного более явным, так или иначе решает проблему.

Смежные вопросы