0
var newcontact = context.Contact.CreateContact(0, "Julio", "Bartowski", DateTime.Now, DateTime.Now, null);

var nAddr = Address.CreateAddress(0, "Home", 0, DateTime.Now, null);
nAddr.Contact = newcontact;
nAddr.Dump();

var newaddress = new Address(){
    Street1 = "5907 Hollow Oak Ct",
    City = "Burke",
    StateProvince = "VA",
    CountryRegion = "US",
    PostalCode = "22015",
    AddressType = "Home",
    ModifiedDate = DateTime.Now
};
newaddress.Contact = newcontact;

this.AddToContacts(newcontact);  //I get an error here when new Addresses are waiting for the ContactID value.
this.SaveChanges();
newcontact.Dump();

私の目標は、Access をバックエンドとして VBscript で記述された 1990 年代の古いクラシック ASP アプリを、SQL Server バックエンドを使用する Visual Studio 11 ベータ版 (2012 年 5 月 26 日) の最新の NuGet から Entity Framework (EF) を使用して MVC3 Razor ページにアップグレードすることです。最終的には、アプリをクライアントのサーバーからクラウドに移動し、Azure に移動します。

ゼロの知識から始めて、オブジェクト リレーショナル インピーダンスの不一致を懸念して、コンソール アプリケーションと LinqPad の両方で EF の例の基本的な紹介を使用しようとしました (クエリを開発およびテストするための非常に高速で便利で簡単な方法:-) Windows 7 ラップトップ。

Julia Lerman の 1st Edition Programming Entity Framework の 130 ページにある BreakAway Geek Adventure (BAGA) デモは、開始するのに適しているように思われました。Self Tracking Entities と Attaching and Detaching、AutoMapper、および Entity Framework のその他の側面についてはあまり知りませんが、基本的な紹介だけで、Microsoft の EF を使用するという考えをトイレに流して、 Ruby-on-Rails ActiveRecord と Amazon Web Services (AWS) の LAMP スタック。

以下の C# EF の例のスニペットは、よく知られている専門家によるもので、非常に単純なはずです... 残念ながら、Stack Overflow に「たぶん」や「かもしれない」などの回答が多数あることは、EF が一般的によく理解されていないことを示しています。

たとえば、ADO.NET Entity Framework と ID 列、および MSDN への参照は役に立ちません。

MSDN は、EF はhttp://blogs.msdn.com/b/dsimmons/archive/2008/08/10/ef-faq-entity-services.aspx#Section_17でサーバーによって生成されたキー値をサポートしていると言っていますが、 私はそれらを信じていません。行/レコード/エンティティをエンティティ セット/テーブルに追加すると、連絡先の ID が EF で返されず、ContactID に応じた後続の挿入が失敗します。

この本の正誤表サイトには、デバッグに関する多くのヒントはありません。Lerman さんの第 1 版と第 2 版では、基本的な EF の基礎がそんなに変わったのでしょうか? 私の新しい子犬が私の新しく手に入れた初版を食べ始めたと私が彼女に言ったとき、彼女は私が彼にそれを返し、彼女の新しい本を手に入れることを提案しました.

他の誰かがこの問題を抱えていますか? 私は短いバスに乗って育ったので、問題は椅子とキーボードの間のどこかにある可能性があります。問題を再現したり、デバッグのヒントを提供したりするのに十分な情報がここにあることを願っています。

Contact テーブルには、データベースで定義された自動インクリメント主キーがあります。T-SQL は次のとおりです。

CREATE TABLE [dbo].[Contact](
    [ContactID] [int] IDENTITY(1,1) NOT NULL,
    [FirstName] [nvarchar](50) NOT NULL,
    [LastName] [nvarchar](50) NOT NULL,
    [Title] [nvarchar](50) NULL,
    [AddDate] [datetime] NOT NULL,
    [ModifiedDate] [datetime] NOT NULL,
    [RowVersion] [timestamp] NOT NULL,
 CONSTRAINT [PK_Contact] PRIMARY KEY CLUSTERED 
(
    [ContactID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

Address テーブルの ContactID には、上記の Contact テーブルとの外部キーの関係があります。

CREATE TABLE [dbo].[Address](
    [addressID] [int] IDENTITY(1,1) NOT NULL,
    [Street1] [nvarchar](50) NULL,
    [Street2] [nvarchar](50) NULL,
    [City] [nvarchar](50) NULL,
    [StateProvince] [nvarchar](50) NULL,
    [CountryRegion] [nvarchar](50) NULL,
    [PostalCode] [nvarchar](50) NULL,
    [AddressType] [nvarchar](50) NOT NULL,
    **[ContactID] [int] NOT NULL**,
    [ModifiedDate] [datetime] NOT NULL,
    [RowVersion] [timestamp] NOT NULL,
 CONSTRAINT [PK_Address] PRIMARY KEY CLUSTERED 
(
    [addressID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

ALTER TABLE [dbo].[Address]  WITH CHECK ADD  CONSTRAINT [FK_Address_Contact] FOREIGN KEY([ContactID])
REFERENCES [dbo].[Contact] ([ContactID])
GO

ALTER TABLE [dbo].[Address] CHECK CONSTRAINT [FK_Address_Contact]
GO

テーブルとその関係をテストします。

DECLARE @ContactID int

INSERT INTO [dbo].[Contact]
           ([FirstName]
           ,[LastName]
           ,[Title]
           ,[AddDate]
           ,[ModifiedDate])
     VALUES
           ('Julio', 'Bartowski', 'Mr.', GETDATE(), GETDATE() )

SET @ContactID = SCOPE_IDENTITY()

PRINT @ContactID

-- this works
INSERT INTO [dbo].[Address]
           ([Street1]
           ,[Street2]
           ,[City]
           ,[StateProvince]
           ,[CountryRegion]
           ,[PostalCode]
           ,[AddressType]
           ,[ContactID]
           ,[ModifiedDate])
     VALUES
           ( '5907 Hollow Oak Ct', 'Suite 1400', 'Burke', 'VA', 'US', '22015', 'Office', @ContactID, GETDATE())

--this raises a referential integrity error (as it should) because there is no Contact with ContactID = 99999
INSERT INTO [dbo].[Address]
           ([Street1]
           ,[Street2]
           ,[City]
           ,[StateProvince]
           ,[CountryRegion]
           ,[PostalCode]
           ,[AddressType]
           ,[ContactID]
           ,[ModifiedDate])
     VALUES
           ( 'BadRef Way', '13th Floor', 'Manhattan', 'NY', 'US', '10004', 'Office', 99999, GETDATE())
GO

INSERT ステートメントが FOREIGN KEY 制約 "FK_Address_Contact" と競合しました。データベース「BreakAway」、テーブル「dbo.Contact」、列「ContactID」で競合が発生しました。ステートメントは終了されました。

    --show the correct inserts worked fine in T-SQL.
SELECT * FROM Contact c 
    LEFT OUTER JOIN Address a 
    ON c.ContactID = a.ContactID
    WHERE c.FirstName LIKE '%Julio%'

Code Through the Painで説明されている SSDL バグが修正されたと仮定しています。念のため、私の Entity Framework ADO.NET Entity Data Model BAModel.EDMX ファイルからの抜粋は、ContactID が Store Schema Definition Language と Conceptual Schema Definition Language の両方で自動インクリメント キー ID であることを示しています。

  <edmx:Runtime>
    <!-- SSDL content -->
    <edmx:StorageModels>
    <Schema Namespace="BreakAwayModel.Store" Alias="Self" Provider="System.Data.SqlClient" ProviderManifestToken="2008" xmlns:store="http://schemas.microsoft.com/ado/2007/12/edm/EntityStoreSchemaGenerator" xmlns="http://schemas.microsoft.com/ado/2009/02/edm/ssdl">
        <EntityContainer Name="BreakAwayModelStoreContainer">
<EntityType Name="Address">
  <Key>
    <PropertyRef Name="addressID" />
  </Key>
  <Property Name="addressID" Type="int" Nullable="false" StoreGeneratedPattern="Identity" />
  <Property Name="Street1" Type="nvarchar" MaxLength="50" />
  <Property Name="Street2" Type="nvarchar" MaxLength="50" />
  <Property Name="City" Type="nvarchar" MaxLength="50" />
  <Property Name="StateProvince" Type="nvarchar" MaxLength="50" />
  <Property Name="CountryRegion" Type="nvarchar" MaxLength="50" />
  <Property Name="PostalCode" Type="nvarchar" MaxLength="50" />
  <Property Name="AddressType" Type="nvarchar" Nullable="false" MaxLength="50" />
  <Property Name="ContactID" Type="int" Nullable="false" />
  <Property Name="ModifiedDate" Type="datetime" Nullable="false" />
  <Property Name="RowVersion" Type="timestamp" Nullable="false" StoreGeneratedPattern="Computed" />
</EntityType>
<EntityType Name="Contact">
  <Key>
    <PropertyRef Name="ContactID" />
  </Key>
  <Property Name="ContactID" Type="int" Nullable="false" StoreGeneratedPattern="Identity" />
  <Property Name="FirstName" Type="nvarchar" Nullable="false" MaxLength="50" />
  <Property Name="LastName" Type="nvarchar" Nullable="false" MaxLength="50" />
  <Property Name="Title" Type="nvarchar" MaxLength="50" />
  <Property Name="AddDate" Type="datetime" Nullable="false" />
  <Property Name="ModifiedDate" Type="datetime" Nullable="false" />
  <Property Name="RowVersion" Type="timestamp" Nullable="false" StoreGeneratedPattern="Computed" />
</EntityType>

<!-- CSDL content -->
<edmx:ConceptualModels>
  <Schema Namespace="BAModel" Alias="Self" xmlns:annotation="http://schemas.microsoft.com/ado/2009/02/edm/annotation" xmlns="http://schemas.microsoft.com/ado/2008/09/edm">
    <EntityContainer Name="BAEntities" annotation:LazyLoadingEnabled="true">

    <EntityType Name="Contact">
      <Key>
        <PropertyRef Name="ContactID" />
      </Key>
      <Property Name="ContactID" Type="Int32" Nullable="false" annotation:StoreGeneratedPattern="Identity" />
      <Property Name="FirstName" Type="String" Nullable="false" MaxLength="50" Unicode="true" FixedLength="false" />
      <Property Name="LastName" Type="String" Nullable="false" MaxLength="50" Unicode="true" FixedLength="false" />
      <Property Name="Title" Type="String" MaxLength="50" Unicode="true" FixedLength="false" />
      <Property Name="AddDate" Type="DateTime" Nullable="false" Precision="3" />
      <Property Name="ModifiedDate" Type="DateTime" Nullable="false" Precision="3" />
      <Property Name="RowVersion" Type="Binary" Nullable="false" MaxLength="8" FixedLength="true" annotation:StoreGeneratedPattern="Computed" />
      <NavigationProperty Name="Addresses" Relationship="BAModel.FK_Address_Contact" FromRole="Contact" ToRole="Address" />
      <NavigationProperty Name="Customer" Relationship="BAModel.FK_Customers_Contact" FromRole="Contact" ToRole="Customers" />
      <NavigationProperty Name="Lodgings" Relationship="BAModel.FK_Lodging_Contact" FromRole="Contact" ToRole="Lodging" />
      <NavigationProperty Name="Payments" Relationship="BAModel.FK_Payment_Contact" FromRole="Contact" ToRole="Payment" />
      </EntityType>

以下は、LinqPad に入力された C# ステートメントですmetadata=res://*/BAModel.csdl|res://*/BAModel.ssdl|res://*/BAModel.msl;。..

ラムダを使用して Contact エンティティをクエリできるということは、EDMX を正しくコンパイルしたことを意味し、私は完全なバカではありません。少なくとも、母はそう言っています。

注: 「これ」は、クエリが DLL アセンブリから実行されている Entities コレクションを参照する LinqPad の方法であり、.Dump() は出力を表示するための LinqPad の方法です。LinqPad では "this" は必要ありませんが、"context" 変数を設定すると、ASP.NET Visual Studio C# コードと同じステートメントを使用できます。

var context = this;

context.Contacts
    .Include("Addresses")
    .OrderByDescending(x => x.ContactID)
    .Take(3)
    //.Single()  //only works if you Take(1)
    .Dump();

このデモをコンソールアプリでも試してみましたが、同様の結果が得られました...

Entity Framework は、新しい ContactID ID を取得しません。SaveChanges() の後で ContactID が 0 のままになり、その後 ContactID に依存する Address 挿入が失敗します。

私は何を間違っていますか?以下の非常に単純化された教育上の例が機能しないのはなぜですか?

var context = this;

var newcontact = new Contact(){
    FirstName = "Julio",
    LastName = "Bartowski",
    Title = "Mr.",
    AddDate = DateTime.Now,
    ModifiedDate = DateTime.Now
};
newcontact.Dump();  //show the entity object before saving to the database

context.AddToContacts(newcontact);
context.SaveChanges();

newcontact.Dump();    //show the entity object after saving to the database

Julia の本によると、newcontact は SaveChanges() の後に更新され、新しい主キーが読み込まれた状態で EntityState が「追加済み」から「未変更」に移行する必要があります。残念ながら、上記の最初の newcontact.Dump() は、最後の newcontact.Dump(): ContactID = 0 と同じことを示しています。

Contact 
BAGA.Contact 
<dl><dt>ContactID</dt><dd>0</dd></dl> 
FirstName Julio 
LastName Bartowski 
Title null  
AddDate 5/27/2012 8:07:11 PM 
ModifiedDate 5/27/2012 8:07:11 PM 
RowVersion null  

上記のコマンドを実行した後に SQL Server Management Studio を見ると、ContactID = 0 が実際に起こったことではないことがわかります。実際には、新しい ContactID の挿入がありました。newcontact エンティティの ContactID プロパティが更新/更新されませんでした。

上記の問題を考えると、有効な ContactID を必要とする依存アドレス挿入 (以下に示す 2 種類の構文を使用) を追加すると、もちろん失敗します。私が読んだものはすべて、「サーバーが生成した値を使用してエンティティの任意の複雑なグラフを作成でき、システムはそれらのグラフ全体の挿入を SaveChanges への 1 回の呼び出しで処理できる」と述べています。うーん...私はできません。

var context = this;

var newcontact = context.Contact.CreateContact(0, "Julio", "Bartowski", DateTime.Now, DateTime.Now, null);

var nAddr = Address.CreateAddress(0, "Home", 0, DateTime.Now, null);
nAddr.Contact = newcontact;
nAddr.Dump();

var newaddress = new Address(){
    Street1 = "5907 Hollow Oak Ct",
    City = "Burke",
    StateProvince = "VA",
    CountryRegion = "US",
    PostalCode = "22015",
    AddressType = "Home",
    ModifiedDate = DateTime.Now
};
newaddress.Contact = newcontact;

this.AddToContacts(newcontact);  //I get an error here when new Addresses are waiting for the ContactID value.
this.SaveChanges();
newcontact.Dump();

LinqPad から Update Exception: エントリの更新中にエラーが発生しました。line context.AddToContacts(newcontact); の詳細については、内部例外を参照してください。

元の値 InvalidOperationException は、この ObjectStateEntry には元の値がないことを示しています。追加または切り離された状態のオブジェクトは、元の値を持つことはできません。

RuntimeMethodInfo は EntityEntry.InternalGetOriginalValues (Boolean readOnly) 名前 InternalGetOriginalValues DeclaringType typeof (EntityEntry)
ReflectedType typeof (EntityEntry)
MemberType メソッド MetadataToken 100678288 Module 4RuntimeModule 4
System.Data.Entity.dll

IsSecurityCritical False IsSecuritySafeCritical False IsSecurityTransparent True MethodHandle 4RuntimeMethodHandle 4
System.RuntimeMethodHandle

属性 PrivateScope、Private、HideBySig CallingConvention Standard、HasThis ReturnType typeof (DbDataRecord)
ReturnTypeCustomAttributes 4RuntimeParameterInfo 4
System.Data.Common.DbDataRecord

ReturnParameter 4RuntimeParameterInfo 4
System.Data.Common.DbDataRecord

IsGenericMethod False IsGenericMethodDefinition False ContainsGenericParameters False MethodImplementationFlags IL IsPublic False IsPrivate True IsFamily False IsAssembly False IsFamilyAndAssembly False IsFamilyOrAssembly False IsStatic False IsFinal False IsVirtual False IsHideBySig True IsAbstract False カスタム IsSpecialName False IsConstructor 4 属性 4

誰かが私の「単純な」問題に対する簡単な答えを持っていて、彼らがうまくいくことを知っています。

4

0 に答える 0