2

我正在使用EF5 fluent-api嘗試建立幾個表之間的關係/約束,我希望這些關係包括級聯刪除,我想我錯過了一些簡單的東西,因爲我已經在下面嘗試過,產生了所述錯誤。很長的帖子,但99%的代碼,不復雜,但試圖重新初始化我的模型時收到下面提到的錯誤 - 有一些預期的約束,但沒有找到。真的抓我的頭在這...任何方向將不勝感激。導航屬性和刪除級聯

namespace Deals.Core.DataAccess.Entities 
{ 
    public abstract class Entity<TEntity> : IEntity<TEntity> where TEntity : Entity<TEntity>, new() 
    { 
     private bool isEmpty; 

     protected Entity() 
     { 
     this.isEmpty = false; 
     } 

     public static TEntity Empty 
     { 
     get 
     { 
      return new TEntity() { IsEmpty = true }; 
     } 
     } 

     public bool Active { get; set; } 
     public bool Deleted { get; set; } 

     [NotMapped] 
     public bool IsEmpty 
     { 
     get 
     { 
      return this.isEmpty; 
     } 

     protected set 
     { 
      this.isEmpty = value; 
     } 
     } 

     public int Version { get; set; } 
    } 

    public class Site : Entity<Site>, ISite 
    { 
     public Guid Id { get; set; } 
     public virtual ICollection<User> Users { get; set; } 
     public virtual Survey Survey { get; set; } 
    } 

    public class Survey : Entity<Survey>, ISurvey 
    { 
     public Guid Id { get; set; } 
     public virtual Site Site { get; set; } 
    } 

    public class User : Entity<User>, IUser 
    { 
     public Guid Id { get; set; } 
     public virtual UserProfile UserProfile { get; set; } 
     public Guid SiteId { get; set; } 
     public virtual Site Site { get; set; } 
    } 

    public class UserProfile : Entity<UserProfile>, IUserProfile 
    { 
     public Guid Id { get; set; } 
     public virtual User User { get; set; } 
    } 
} 

namespace Deals.Core.DataAccess.Models 
{ 
    public class Context : DbContext, IContext 
    { 
     public DbSet<Site> Sites { get; set; } 
     public DbSet<Survey> Surveys { get; set; } 
     public DbSet<User> Users { get; set; } 
     public DbSet<UserProfile> UserProfiles { get; set; } 

     protected override void OnModelCreating(DbModelBuilder modelBuilder) 
     { 
     this.MapSite(modelBuilder); 
     this.MapSurvey(modelBuilder); 
     this.MapUser(modelBuilder); 
     this.MapUserProfile(modelBuilder); 

     Database.SetInitializer(new MigrateDatabaseToLatestVersion<Context, ContextConfiguration>()); 

     base.OnModelCreating(modelBuilder); 
     } 

     protected virtual void MapSite(DbModelBuilder modelBuilder) 
     { 
     // Ignore the IsEmpty property. 
     this.MapEntity<Site>(modelBuilder); 

     modelBuilder.Entity<Site>().HasKey(p => p.Id); 
     modelBuilder.Entity<Site>().HasOptional(p => p.Survey); 
     modelBuilder.Entity<Site>().HasOptional(p => p.Users); 
     } 

     protected virtual void MapUser(DbModelBuilder modelBuilder) 
     { 
     // Ignore the IsEmpty property. 
     this.MapEntity<User>(modelBuilder); 

     modelBuilder.Entity<User>().HasKey(p => p.Id); 
     modelBuilder.Entity<User>().HasRequired(p => p.Site).WithMany(p => p.Users).HasForeignKey(p => p.SiteId); 
     } 

     protected virtual void MapUserProfile(DbModelBuilder modelBuilder) 
     { 
     // Ignore the IsEmpty property. 
     this.MapEntity<UserProfile>(modelBuilder); 

     modelBuilder.Entity<UserProfile>().HasKey(p => p.Id); 

     // Why does adding .WillCascadeOnDelete() look for a user_id constraint on UserProfile that does not exist? 
     //modelBuilder.Entity<UserProfile>().HasRequired(p => p.User).WithRequiredPrincipal(user => user.UserProfile); 
     //// .WillCascadeOnDelete(); 
     modelBuilder.Entity<UserProfile>().HasRequired(p => p.User); 
     } 

     protected virtual void MapSurvey(DbModelBuilder modelBuilder) 
     { 
     // Ignore the IsEmpty property. 
     this.MapEntity<Survey>(modelBuilder); 

     modelBuilder.Entity<Survey>().HasKey(p => p.Id); 
     modelBuilder.Entity<Survey>().HasRequired(p => p.Site); 
     //modelBuilder.Entity<Site>().HasOptional(p => p.Survey).WithOptionalPrincipal().WillCascadeOnDelete(); 
     modelBuilder.Entity<Survey>().Property(p => p.SurveyXml).HasColumnType("xml").IsRequired(); 
     } 

     #region Generic Mapping 
     protected virtual void MapEntity<T>(DbModelBuilder modelBuilder) where T : Entity<T>, new() 
     { 
     // Ignore the IsEmpty property. 
     modelBuilder.Entity<T>() 
      .Ignore(p => p.IsEmpty); 
     } 

     #endregion Generic Mapping 
    } 
} 

SQL生成:

create table [dbo].[Sites] (
    [Id] [uniqueidentifier] not null, 
    [Url] [nvarchar](max) null, 
    [Description] [nvarchar](max) null, 
    [Active] [bit] not null, 
    [Deleted] [bit] not null, 
    [Version] [int] not null, 
    primary key ([Id]) 
); 
create table [dbo].[Surveys] (
    [Id] [uniqueidentifier] not null, 
    [SurveyXml] [xml] not null, 
    [Active] [bit] not null, 
    [Deleted] [bit] not null, 
    [Version] [int] not null, 
    primary key ([Id]) 
); 
create table [dbo].[Users] (
    [Id] [uniqueidentifier] not null, 
    [UserName] [nvarchar](max) null, 
    [Password] [nvarchar](max) null, 
    [LastLogin] [datetime] not null, 
    [SiteId] [uniqueidentifier] not null, 
    [Active] [bit] not null, 
    [Deleted] [bit] not null, 
    [Version] [int] not null, 
    primary key ([Id]) 
); 
create table [dbo].[UserProfiles] (
    [Id] [uniqueidentifier] not null, 
    [FirstName] [nvarchar](max) null, 
    [LastName] [nvarchar](max) null, 
    [MiddleInitial] [nvarchar](max) null, 
    [Honorific] [nvarchar](max) null, 
    [Email] [nvarchar](max) null, 
    [Active] [bit] not null, 
    [Deleted] [bit] not null, 
    [Version] [int] not null, 
    primary key ([Id]) 
); 

Сan't得到 「ON DELETE CASCADE」 在這裏:

alter table [dbo].[Surveys] add constraint [Site_Survey] foreign key ([Id]) references [dbo].[Sites]([Id]); 

這是一件好事:

alter table [dbo].[Users] add constraint [User_Site] foreign key ([SiteId]) references [dbo].[Sites]([Id]) on delete cascade; 

無法獲得「在刪除級聯」這裏:

alter table [dbo].[UserProfiles] add constraint [UserProfile_User] foreign key ([Id]) references [dbo].[Users]([Id]); 

如果我這樣做:

modelBuilder.Entity<UserProfile>() 
     .HasRequired(p => // p.User) 
     .WithRequiredPrincipal(user => user.UserProfile) 
     .WillCascadeOnDelete(); 

// Instead of this: 
modelBuilder.Entity<UserProfile>().HasRequired(p => p.User); 

// The sql that is generated looks correct: 
alter table [dbo].[Users] add constraint [UserProfile_User] 
    foreign key ([Id]) references [dbo].[UserProfiles]([Id]) on delete cascade; 

不過,我想運行測試時重新初始化我的模型時得到這個錯誤;怎麼了FK_dbo.UserProfiles_dbo.Users_Id?

Test Name: SiteRepository_Remove_TestPasses 
Test FullName: Deals.Core.Tests.Deals.Core.DataLibrary.Tests.Integration.SiteRepositoryIntegrationTests.SiteRepository_Remove_TestPasses 
Test Source: c:\Dev\Deals\Deals.Core.Tests\Deals.Core.DataLibrary.Tests\Integration\SiteRepository.Integration.Tests.cs : line 51 
Test Outcome: Failed 
Test Duration: 0:00:01.4034458 

Result Message: 
Initialization method Deals.Core.Tests.Deals.Core.DataLibrary.Tests.Integration.SiteRepositoryIntegrationTests.TestInitialize threw exception. System.Data.SqlClient.SqlException: System.Data.SqlClient.SqlException: 'FK_dbo.UserProfiles_dbo.Users_Id' is not a constraint. 
Could not drop constraint. See previous errors.. 
Result StackTrace: 
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction) 
    at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) 
    at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) 
    at System.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String methodName, Boolean async, Int32 timeout) 
    at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, String methodName, Boolean sendToPipe, Int32 timeout, Boolean asyncWrite) 
    at System.Data.SqlClient.SqlCommand.ExecuteNonQuery() 
    at System.Data.Entity.Migrations.DbMigrator.ExecuteSql(DbTransaction transaction, MigrationStatement migrationStatement) 
    at System.Data.Entity.Migrations.DbMigrator.ExecuteStatements(IEnumerable`1 migrationStatements) 
    at System.Data.Entity.Migrations.DbMigrator.AutoMigrate(String migrationId, XDocument sourceModel, XDocument targetModel, Boolean downgrading) 
    at System.Data.Entity.Migrations.DbMigrator.Upgrade(IEnumerable`1 pendingMigrations, String targetMigrationId, String lastMigrationId) 
    at System.Data.Entity.MigrateDatabaseToLatestVersion`2.InitializeDatabase(TContext context) 
    at System.Data.Entity.Internal.InternalContext.PerformInitializationAction(Action action) 
    at System.Data.Entity.Internal.InternalContext.PerformDatabaseInitialization() 
    at Deals.Core.DataAccess.UnitOfWorkCore.ForceDatabaseInititialization() in c:\Dev\Deals\Deals.Core.DataAccess\UnitOfWorkCore.cs:line 164 
    at Deals.Core.Tests.Deals.Core.DataLibrary.Tests.Integration.SiteRepositoryIntegrationTests.TestInitialize() in c:\Dev\Deals\Deals.Core.Tests\Deals.Core.DataLibrary.Tests\Integration\SiteRepository.Integration.Tests.cs:line 28 
+3

真的,真的:(你不能把這個問題煮到相關部分來解決你的問題嗎?我無法想象像'Description'等屬性以及屬性上方的所有摘要元素對您的問題起到任何作用。向下滾動代碼以找到重要的作品是非常糟糕的。我已經停下來發現他們是誠實的。 – Slauma

+0

@Slauma - 你認真嗎?這不是太多的代碼,另外,一個人抱怨太多了,另一個你沒有足夠的包含。 – gangelo

+0

對於我來說,這種混合的c#,註釋,sql,異常消息,不相關的部分等等都在一個很長的部分是可怕的。沒關係,有人可能會通過它的神經... – Slauma

回答

0

這個固定

看來,我的數據庫沒有被刪除並重新創建每次測試運行...

在我的DbContext

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
     { 
     Database.SetInitializer(new MigrateDatabaseToLatestVersion<Context, ContextConfiguration>()); 

     base.OnModelCreating(modelBuilder); 
     } 

我的遷移配置

public class ContextConfiguration : DbMigrationsConfiguration<Context> 
    { 
     public ContextConfiguration() 
     { 
     this.AutomaticMigrationsEnabled = true; 
     this.AutomaticMigrationDataLossAllowed = true; 
     } 
    } 

在我的測試

[TestInitialize] 
     public override void TestInitialize() 
     { 
     // Force model updates. 
     using (var uow = UnitOfWorkFactory.Instance.Create<UnitOfWorkCore>(DefaultConnectionString)) 
     { 
      uow.Database.Initialize(force: false); 
     } 

     // begin transaction 
     this.transactionScope = new TransactionScope(); 

     this.unitOfWork = UnitOfWorkFactory.Instance.Create<UnitOfWorkCore>(DefaultConnectionString); 
     } 

我改變了一些事情到此並沒有任何問題 * 我改變了一些事情到此並沒有任何問題 * 我改變了一些事情到此並沒有任何問題

在我的測試

[TestInitialize] 
     public override void TestInitialize() 
     { 
     // Force model updates. 

     // I CHANGED TO THIS: 
     Database.SetInitializer(new DropCreateDatabaseAlways<Context>()); 

     using (var uow = UnitOfWorkFactory.Instance.Create<UnitOfWorkCore>(DefaultConnectionString)) 
     { 
      uow.Database.Initialize(force: false); 
     } 

     // begin transaction 
     this.transactionScope = new TransactionScope(); 

     this.unitOfWork = UnitOfWorkFactory.Instance.Create<UnitOfWorkCore>(DefaultConnectionString); 
     } 
0

如果要在刪除父對象時刪除子對象,則必須從關聯的父側進行配置。首先在子對象[Required]中輸入Foreign Key屬性,然後輸入以下代碼。

您應該也知道,不像one-to-many relationshipsone-to-one relationships級聯刪除沒有啓用默認情況下,甚至沒有所需的關係。你必須定義級聯刪除了一個一對一的關係明確:

+0

這看起來倒退了,我的關係是Site-> User-> UserProfile |網站 - >調查? – gangelo

+0

@gangelo無論如何,它必須讀你的問題。我的答案中的關鍵是「你必須總是定義級聯刪除以明確一對一的關係」。並確保它從父對象完成。 – Komengem