2017-07-25 5 views
4

などの非ヌルフィールドを保存しようとしている私は、特定のプロバイダにStoreSku.Dataを結ぶにしたくないので、私はStoreSku.Providerにそのreposonsibilityを移動した二つのプロジェクトDbContextがnull

StoreSku.Data - Depends On: Microsoft.EntityFrameworkCore 
StoreSku.Provider - Depends On: StoreSku.Data, Microsoft.EntityFrameworkCore.SqlServer 

を持っています。それはかなり冗長ですが、あなたが見ることができるように

var optionsBuilder = new DbContextOptionsBuilder(); 
optionsBuilder.UseSqlServer(connectionString); 

var conventions = new ConventionSet(); 
var modelBuilder = new ModelBuilder(conventions); 

modelBuilder.Entity<StoreSkuUpdateRequest>().HasKey(request => request.Id); 
modelBuilder.Entity<StoreSkuUpdateRequest>().Property(request => request.Id).UseSqlServerIdentityColumn(); 
modelBuilder.Entity<StoreSkuUpdateRequest>().Property(request => request.StoreNumber).ValueGeneratedNever(); 
modelBuilder.Entity<StoreSkuUpdateRequest>().Property(request => request.BusinessDate).ValueGeneratedNever(); 
modelBuilder.Entity<StoreSkuUpdateRequest>().Property(request => request.Timestamp).ValueGeneratedNever(); 
modelBuilder.Entity<StoreSkuUpdateRequest>().HasMany(request => request.RequestedUpdates).WithOne(update => update.UpdateRequest); 
modelBuilder.Entity<StoreSkuUpdateRequest>().HasMany(request => request.RelatedUpdates).WithOne(relatedUpdate => relatedUpdate.UpdateRequest); 
modelBuilder.Entity<StoreSkuUpdateRequest>().ForSqlServerToTable("StoreSkuUpdateRequest"); 

modelBuilder.Entity<StoreSkuAvailabilityUpdate>().HasOne(update => update.UpdateRequest).WithMany(request => request.RequestedUpdates); 
modelBuilder.Entity<StoreSkuAvailabilityUpdate>().HasMany(update => update.RelatedUpdates).WithOne(relatedUpdate => relatedUpdate.RequestedUpdate); 
modelBuilder.Entity<StoreSkuAvailabilityUpdate>().ForSqlServerToTable("RequestedStoreSkuUpdate"); 

modelBuilder.Entity<RelatedStoreSkuUpdate>().HasOne(relatedUpdate => relatedUpdate.RequestedUpdate).WithMany(update => update.RelatedUpdates); 
modelBuilder.Entity<RelatedStoreSkuUpdate>().HasOne(relatedUpdate => relatedUpdate.UpdateRequest).WithMany(request => request.RelatedUpdates); 
modelBuilder.Entity<RelatedStoreSkuUpdate>().ForSqlServerToTable("RelatedStoreSkuUpdate"); 

optionsBuilder.UseModel(modelBuilder.Model); 

DbContextOptions options = optionsBuilder.Options; 

:私はStoreSku.Provider内のモデルとオプションを作成し、次のコードを使用してDbContextにオプションを渡しています。これらの呼び出しのすべてが必要かどうかは、別の質問です。私の質問は、これらの線に沿って、より焦点を当て:

modelBuilder.Entity<StoreSkuUpdateRequest>().Property(request => request.StoreNumber).ValueGeneratedNever(); 
modelBuilder.Entity<StoreSkuUpdateRequest>().Property(request => request.BusinessDate).ValueGeneratedNever(); 
modelBuilder.Entity<StoreSkuUpdateRequest>().Property(request => request.Timestamp).ValueGeneratedNever(); 

私はに実行したエラーが、私はこれらの行を持っていない場合、私は次のエラーを取得することです:

Cannot insert the value NULL into column 'StoreNumber', table 'dbo.StoreSkuUpdateRequest'; column does not allow nulls. INSERT fails. 
The statement has been terminated. 
Cannot insert the value NULL into column 'BusinessDate', table 'dbo.StoreSkuUpdateRequest'; column does not allow nulls. INSERT fails. 
The statement has been terminated. 
Cannot insert the value NULL into column 'Timestamp', table 'dbo.StoreSkuUpdateRequest'; column does not allow nulls. INSERT fails. 
The statement has been terminated. 

スキーマのこの表は

CREATE TABLE [dbo].[StoreSkuUpdateRequest](
[Id] [bigint] IDENTITY(1,1) NOT NULL, 
[StoreNumber] [int] NOT NULL, 
[BusinessDate] [date] NOT NULL, 
[Timestamp] [datetime] NOT NULL) 

とモデルである

public sealed class StoreSkuUpdateRequest 
{ 
    [Required] 
    public long Id { get; set; } 

    [Required] 
    public int StoreNumber { get; set; } 

    [Required] 
    public DateTime BusinessDate { get; set; } 

    [Required] 
    public DateTime Timestamp { get; set; } 
} 

そして、呼び出し元のコード:

using (Context) 
{ 
    var request = new StoreSkuUpdateRequest 
    { 
     StoreNumber = 12345, 
     BusinessDate = DateTime.UtcNow, 
     Timestamp = DateTime.UtcNow 
    }; 
    Context.StoreSkuAvailabilityUpdateRequests.Add(request); 

    Context.SaveChanges(); 
} 

そして、生成されたSQLコマンドは、私はこれらのプロパティのそれぞれに対してValueGeneratedNever();を指定しなければならないのはなぜ

BEGIN TRANSACTION 

SET NOCOUNT ON; 
INSERT INTO [StoreSkuUpdateRequest] 
DEFAULT VALUES; 
SELECT [Id] 
FROM [StoreSkuUpdateRequest] 
WHERE @@ROWCOUNT = 1 AND [Id] = scope_identity(); 

ROLLBACK TRANSACTION 

のですか?なぜEFCoreはそれらをnullとして保存しようとしていますか?

+0

StoreSkuUpdateRequestとStoreSkuAvailabilityUpdateの関係は何ですか?私は、あなたがUpdateRequestを作成しているのにそれをAvailabilityUpdateRequestsに追加しているという点でちょっと混乱していますか?両者(歴史的)の間には関係があるようですが、EFが解決しなければならないFKの関係に陥った場合、Insert + Updateシナリオのようなことが起こっているかもしれません。 SQLプロファイラで、SaveChangesのDBに送信されている内容を正確に確認してください。 –

+2

あなたの問題の中心的な原因は、** empty ** 'ConventionSet'での' ModelBuilder'の作成です。一方、 'OnModelCreating'に渡される' ModelBuilder'はすべてのEF Core規則を含む 'ConventionSet'で初期化されます。 –

+0

@IvanStoev私はそれが事実かもしれないと思っていましたが、私はあらゆる種類のAllConventionsSetを見つけることができず、すべての実装は「このAPIはEntity Frameworkコアインフラストラクチャをサポートしています。あなたのコード。このAPIは将来のリリースで変更されるか、または削除される可能性があります。 ' – Zymus

答えて

1

は、オリジナルのポストでイワンStoevからのコメントに基づいて、私はトリアージで議論https://github.com/aspnet/EntityFramework/issues/3529

からこの少しつまずいと人々は心配する必要がないように、我々はModelBuilderの工場を持っていなければならないことを決めました(特に、最初のリリースでは慣習が「内部」なので)。

人々はちょうどこのようなものまでが(これは工場出荷時に静的なcreate()メソッドではなく、デフォルトのctorのは、DIとうまく再生されないたため、工場を取得するためのデフォルトのctorであることに注意)を作成することができますDIに登録されている

var builder = SqlServerModelBuilderFactory.Create()

あなたはそれが、我々はあなただけ解決できるものを登録しますDIから、すべてのそれのサービスを取得したい場合は代わりに、...あなたは同じロガーを取得します、など(さらに、タイプマッパーなどをオーバーライドした場合は、それらのサービスも取得します)。

sp.AddEntityFramework() .AddSqlCompact() .AddNpgSql() .AddSqlServer();

var builder = sp.GetService<ISqlServerModelBuilderFactory>().Create();

私はSqlServerConventionSetBuilderがあったかどうかを調査するために私を導いSqlServerModelBuilderFactoryクラスを、見つけることができませんでした。ありました。

だからすぐに私を固定

var conventions = SqlServerConventionSetBuilder.Build(); 

var conventions = new ConventionSet(); 

からそれを変えます。