2012-05-14 2 views
4

После нескольких часов проб и ошибок я добрался до этого thread, в котором объясняется, как установить One- To-Many и отношения «один-к-одному» с теми же двумя типами.Entity Framework 5.0b2 Первый код: один-ко-многим и один-к-одному для одной и той же таблицы WITH WITH Cascade Delete

Однако, я не могу получить эту работу с Cascade Delete:

Метательные:. «Невозможно определить правильный порядок для зависимых операций Зависимости может существовать из-за ограничения внешнего ключа, требование модели, или хранящиеся в хранилищах значения ". (System.Data.UpdateException) Сообщение об исключении = «Невозможно определить действительный порядок для зависимых операций. Зависимости могут существовать из-за для ограничений внешнего ключа, требований к модели или генерируемых магазином значений .», Тип исключения = «Система .Data.UpdateException "

Это происходит только в том случае, если я не отменяю соотношение 1: 1 (см. Код ниже), что, я думаю, имеет смысл, если оно создаст неверную ссылку. Мне просто интересно, есть ли лучший способ представить это.

Пример кода:

class Program 
{ 
    static void Main(string[] args) 
    { 
     Database.SetInitializer(new DropCreateDatabaseAlways<Context>()); 

     using (var ctx = new Context()) 
     { 
      var user = new User(); 

      ctx.Users.Add(user); 
      ctx.SaveChanges(); 

      var source = new PaymentSource(); 
      user.PaymentSources = new Collection<PaymentSource>(); 
      user.PaymentSources.Add(source); 
      user.DefaultPaymentSource = source; 
      ctx.SaveChanges(); 

      // if I don't do this, I get ordering exception 
      user.DefaultPaymentSource = null; 
      ctx.SaveChanges(); 

      ctx.Users.Remove(user); 
      ctx.SaveChanges(); 

      Assert.Equal(0, ctx.Users.Count()); 
      Assert.Equal(0, ctx.PaymentSources.Count()); 
     } 
    } 
} 

public class User 
{ 
    public int Id { get; set; } 

    public virtual ICollection<PaymentSource> PaymentSources { get; set; } 
    public virtual PaymentSource DefaultPaymentSource { get; set; } 
    public int? DefaultPaymentSourceId { get; set; } 
} 

public class PaymentSource 
{ 
    public int Id { get; set; } 
    public virtual User User { get; set; } 
    public int UserId { get; set; } 
} 

public class Context : DbContext 
{ 
    public DbSet<User> Users { get; set; } 
    public DbSet<PaymentSource> PaymentSources { get; set; } 

    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     base.OnModelCreating(modelBuilder); 

     modelBuilder.Entity<User>() 
      .HasOptional(u => u.DefaultPaymentSource) 
      .WithMany() 
      .HasForeignKey(u => u.DefaultPaymentSourceId) 
      .WillCascadeOnDelete(false); 

     modelBuilder.Entity<PaymentSource>() 
      .HasRequired(p => p.User) 
      .WithMany(p => p.PaymentSources) 
      .HasForeignKey(p => p.UserId) 
      .WillCascadeOnDelete(); 
    } 
} 
+0

Не могли бы вы объяснить две таблицы, которые нуждаются в соотношении 1-1 и 1- *? более конкретно: предполагается ли абстракция древовидной структуры? –

+0

Я думал, что модель не требует пояснений, но, я думаю, нет. Ну, «Пользователь» имеет N 'PaymentSource's (1: N), а также сохраняет значение по умолчанию (1: 1, 0: 1 - строгий.) – georgiosd

ответ

2

я перечислил другие варианты, чтобы описать вашу абстракцию:

А.

Как об использовании 3 таблицы так:

user 1-* paymentSource 
user 1-0..1 DefaultPaymentSource 
DefaultPaymentSource 0..1-1 PaymentSource 

или это:

B.

user 1-* paymentSource 
user 1-0..1 DefaultPaymentSource 
DefaultPaymentSource --derive from--> PaymentSource 

или это:

C.

user 1-* paymentSource 
PaymentSource has addtional boolean field for "IsDefault" 

Я голосую за выбор B, как лучший.

Я уверен, что наличие двух отношений, исходящих из одной исходной таблицы, в одну и ту же таблицу назначения не будет хорошей идеей. Возможно, это нарушение некоторых правил или шаблонов, касающихся лучшей практики баз данных.

+0

Я против B и C, потому что они могут легко создавать проблемы если вам не удалось сохранить только один код * DefaultPaymentSource'in. Другими словами, идеальная модель гарантирует, что a) только один «PaymentSource» может быть по умолчанию в любое время без логики и b) не создает проблем, если по умолчанию удаляется (моя модель этого не делает). Как А) перевести код? Не уверен, что я полностью это понимаю. – georgiosd

+0

hmm .. yup - C будет иметь эту проблему, которую вы описали. Но A или B можно использовать без проблем с несколькими значениями по умолчанию.Однако в обоих случаях вам нужно будет убедиться, что при удалении источника он не должен использоваться по умолчанию. в отношении кода, вы просто создаете метод для удаления и заполнения его с условиями, которые вам нужны, прежде чем вы удалите .. но я понимаю - вы ищете что-то, что более каскадируется в операциях - уверены ли вы, что EF позволяет вам настраивать таким образом ? (imho) Я так не думаю .. но если я ошибаюсь, дайте мне знать. –

+0

Возможно, вы правы, и это не позволяет, я тоже не знаю :) - отсюда вопрос! Можете ли вы подробнее остановиться на A? B будет иметь много бокса/распаковки в коде. – georgiosd