2

ユースケースの例とDB内のオブジェクトの個別の作成EFコードファースト:TFT継承

ユーザーが(Usersテーブルにレコードを追加する)、ウェブサイト上で登録しています。その後、電子メールに行き、登録を確認します。確認リンクは人編集フォームのページにリダイレクトされ、ユーザーはフォームを入力して送信します(Personsテーブルにレコードを追加します)。

技術説明

IはEFモデルで定義された単純な2オブジェクト表ペル型継承を有します。

エンティティ

public class User 
{ 
    public Guid Id { get; set; } 
    public string Name { get; set; } 
    public string Email { get; set; } 
    public string Password { get; set; } 
} 

public class Person : User 
{ 
    public string FirstName { get; set; } 
    public string MiddleName { get; set; } 
    public string LastName { get; set; } 
} 

データベース

public class MainDataContext : DbContext 
{ 
    public DbSet<User> Users { get; set; } 
    public DbSet<Person> Persons { get; set; } 

    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     base.OnModelCreating(modelBuilder); 
     var configs = modelBuilder.Configurations; 
     configs.Add(new UserConfiguration()); 
     configs.Add(new PersonConfiguration()); 
    } 
} 

構成

internal class UserConfiguration : EntityTypeConfiguration<User> 
{ 
    internal UserConfiguration() 
    { 
     ToTable("Users"); 

     HasKey(x => x.Id); 

     Property(x => x.Id) 
      .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); 
     Property(x => x.Name) 
      .IsRequired() 
      .HasMaxLength(128); 
     Property(x => x.Password) 
      .IsRequired() 
      .HasMaxLength(128); 
     Property(x => x.Email) 
      .IsRequired() 
      .HasMaxLength(128); 
    } 
} 
internal class PersonConfiguration : EntityTypeConfiguration<Person> 
{ 
    internal PersonConfiguration() 
    { 
     ToTable("Persons"); 

     Property(x => x.FirstName) 
      .IsRequired() 
      .HasMaxLength(16); 
     Property(x => x.MiddleName) 
      .IsOptional() 
      .HasMaxLength(16); 
     Property(x => x.LastName) 
      .IsRequired() 
      .HasMaxLength(16); 
    } 
} 
一貫DbSetsにリンク(FK)オブジェクトを作成する必要が

、このような何か:

var db = new MainDataContext(); 
    var user = new User 
    { 
     Name = "someUser", 
     Password = "somePassword", 
     Email = "someEmail" 
    }; 
    db.Users.Add(user); 
    db.SaveChanges(); 
    // After some time in other some place 
    var person = new Person 
    { 
     Id = user.Id, 
     FirstName = "someFirstName", 
     LastName = "someLastName" 
    }; 
    db.Persons.Add(person); 
    db.SaveChanges(); 

最後のSaveChanges DbEntityValidationErrorをキャッチした後:「検証は、1つのまたは複数のエンティティに失敗しました。詳細については、「EntityValidationErrors」プロパティを参照してください。」必要なユーザーのフィールドの3個の検証エラーがあります。

別途FK(継承)でacociatedさDbSetsにエントリを追加する方法は?

UPDATE

私は1つの解決策を見つけましたが、古いユーザーを削除する必要があります。ユーザーテーブルが他のテーブルに関連付けられている場合、削除することができなくなるため、取り除かずにこれを行う必要があります。

var db = new MainDataContext(); 
    var user = new User 
    { 
     Name = "someUser", 
     Password = "somePassword", 
     Email = "someEmail" 
    }; 
    db.Users.Add(user); 
    db.SaveChanges(); 
    // After some time in other some place 
    var person = new Person 
    { 
     Id = user.Id, 
     Name = user.Name, 
     Password = user.Password, 
     Email = user.Email, 
     FirstName = "someFirstName", 
     LastName = "someLastName" 
    }; 
    db.Users.Remove(user); 
    db.Persons.Add(person); 
    db.SaveChanges(); 

しかし、もう1つの問題がありました - personオブジェクトの新しいGuidが生成されました。

どのようにユーザーの古いレコードを削除せずに問題を解決するには?

+0

ユーザーはユーザーを継承するため、名前、パスワード、および電子メールを指定する必要があります。データベースはどのように見えますか? Personテーブルには、UserテーブルのフィールドまたはFKだけのUserテーブルのすべてのフィールドがありますか?後であれば、エンティティは間違っています。 – cadrell0

+0

@ cadrell0私が前に述べたように、テーブルをオブジェクト階層にマップする方法では、テーブルごとの型(ユーザーテーブルにはFKのみ)を使用します。以下はdb図の[image](http://dl.dropbox.com/u/5522431/TPT.png)です。 – ebashmakov

+0

なぜPersonはUserから継承しているのですか? – cadrell0

答えて

1

ユースケースの更新を含めた後:

あなたはここに継承を使用しないでください。あなたは組成とエンティティ間の1対1の関係を使用する必要があります

public class User 
{ 
    public Guid Id { get; set; } 
    public string Name { get; set; } 
    public string Email { get; set; } 
    public string Password { get; set; } 
    public virtual UserInfo Information{get;set;} 
} 

internal class UserConfiguration : EntityTypeConfiguration<User> 
{ 
    internal UserConfiguration() 
    { 
     ToTable("Users"); 

     HasKey(x => x.Id); 

     Property(x => x.Id) 
      .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); 
     Property(x => x.Name) 
      .IsRequired() 
      .HasMaxLength(128); 
     Property(x => x.Password) 
      .IsRequired() 
      .HasMaxLength(128); 
     Property(x => x.Email) 
      .IsRequired() 
      .HasMaxLength(128);   
    } 
} 

public class UserInfo 
{ 
    [ForeignKey("InfosUser")] 
    [Key] 
    public UserId {get;set;} 
    public string FirstName { get; set; } 
    public string MiddleName { get; set; } 
    public string LastName { get; set; } 
    public virtual User InfosUser {get;set;} 
} 

internal class UserInfoConfiguration : EntityTypeConfiguration<UserInfo> 
{ 
    internal UserInfoConfiguration() 
    { 
     ToTable("Persons"); 

     Property(x => x.FirstName) 
      .IsRequired() 
      .HasMaxLength(16); 
     Property(x => x.MiddleName) 
      .IsOptional() 
      .HasMaxLength(16); 
     Property(x => x.LastName) 
      .IsRequired() 
      .HasMaxLength(16); 
     HasRequired(ui=>ui.InfosUser).WithOptional(u=>u.Information) 
    } 
} 

をし、それを使用します。

var db = new MainDataContext(); 
    var user = new User 
    { 
     Name = "someUser", 
     Password = "somePassword", 
     Email = "someEmail" 
    }; 
    db.Users.Add(user); 
    db.SaveChanges(); 
    // After some time in other some place 
    var user = db.GetPersonFromDb(Id);// Get early saved person from db 
    var information = new UserInfo 
    { 
     FirstName = "someFirstName", 
     LastName = "someLastName", 
    } 
    user.Information = information; 
    db.SaveChanges(); 
+0

申し訳ありませんが、解決策は適合しません。なぜなら、FirstName列とLastName列をPersons表に必要としたいからです。 – ebashmakov

+0

ユースケースについて説明できますか?なぜデータの半分を保存してから、他のデータを追加する必要がありますか?あなたは何をしたいのですか(前の行を削除することによる回避策を除いて)はできませんが、あなたのユースケースには別の方法があると確信しています。 –

+0

私はポストを更新しました。チェックアウトしてください。 – ebashmakov

0

問題が作成されたオブジェクトは、Personオブジェクトではないということのようです。 Person.idの値をPersonテーブルに挿入すると、そのPersonをPersonとして見つけ出し、それらをudpateすることができます。

 Guid id; 
     using (var db = new MainDataContext()) 
     { 
      var user = new User 
      { 
       Name = "someUser", 
       Password = "somePassword", 
       Email = "someEmail" 
      }; 
      db.Users.Add(user); 
      db.SaveChanges(); 
      id = user.Id; 
     } 

     // After some time in other some place 
     //pause here and insert the id GUID into the Person table 

     using (var db = new MainDataContext()) 
     { 
      var person = db.Persons.Find(id); 
      person.FirstName = "someFirstName"; 
      person.LastName = "someLastName"; 
      db.SaveChanges(); 
     } 

EF以外のPersonテーブルにUserのIDを追加すると、希望のアップキャストが達成されます。データベースを直接更新して、UserからPersonにオブジェクトを「昇格」することができます。

関連する問題