2016-10-05 7 views
0

私は子エンティティが付加された単純なオブジェクトを持っています。 デタッチされたオブジェクトを更新すると、その子オブジェクトのプロパティは保存されません。私はこのフォームで多くの投稿を読んでいますが、なぜ更新していないのか分かりません。分離されたエンティティはプロパティを更新しません

ここでエンティティを更新するための内部メソッドを参照してください:

public class HtmlContent : ITextContentItem, ICreateStamp, IEditStamp, IImmutable 
{ 
    // ReSharper disable once UnusedMember.Local 
    private HtmlContent() 
    { 

    } 

    public HtmlContent(string name, string description, string text, DateTime creationDate, 
     DateTime? lastEditDate, ApplicationUser createdBy, ApplicationUser lastEditedBy) 
    { 
     this.Name = name; 
     this.Description = description; 
     this.Text = text; 
     this.CreationDate = creationDate; 
     this.LastEditDate = lastEditDate; 
     this.CreatedBy = createdBy; 
     this.LastEditedBy = lastEditedBy; 
    } 

    public HtmlContent(int id, string name, string description, string text, DateTime creationDate, 
     DateTime? lastEditDate, ApplicationUser createdBy, ApplicationUser lastEditedBy) 
     : this(name, description, text, creationDate, lastEditDate, createdBy, lastEditedBy) 
    { 
     this.Id = id; 
    } 

    public int Id { get; private set; } 

    public string Name { get; private set; } 

    public string Description { get; private set; } 

    public string Text { get; private set; } 

    public DateTime CreationDate { get; private set; } 

    public DateTime? LastEditDate { get; private set; } 

    public ApplicationUser CreatedBy { get; private set; } 

    public ApplicationUser LastEditedBy { get; private set; } 

    internal HtmlContent SetLastEditInfo(DateTime? lastEditDate, ApplicationUser lastEditedBy) 
    { 
     if ((lastEditDate.HasValue && lastEditedBy == null) || 
      (!lastEditDate.HasValue && lastEditedBy != null)) 
     { 
      throw new InvalidOperationException($"{nameof(lastEditDate)} and {nameof(lastEditedBy)} must be used together"); 
     } 

     return new HtmlContent(this.Id, this.Name, this.Description, this.Text, this.CreationDate, lastEditDate, this.CreatedBy, lastEditedBy); 
    } 

    internal HtmlContent UpdateHtmlContent(string name, string description, string text) 
    { 
     return new HtmlContent(this.Id, name, description, text, this.CreationDate, this.LastEditDate, this.CreatedBy, this.LastEditedBy); 
    } 
} 

は、ここで更新方法を参照してください。

public async Task Edit(int id, string name, string description, string text) 
{ 
    try 
    { 
     var content = await this.WithId(id); 
     this.db.Entry(content).State = EntityState.Detached; 

     var currentDate = DateTime.UtcNow; 
     var lastEditedBy = this.userProvider.GetCurrentUser(); 

     content = content.SetLastEditInfo(currentDate, lastEditedBy); 
     content = content.UpdateHtmlContent(name, description, text); 

     this.db.Entry(content).State = EntityState.Modified; 
     await this.db.SaveChangesAsync(); 
    } 
    catch (System.Data.Entity.Validation.DbEntityValidationException ex) 
    { 
     var errors = ex.EntityValidationErrors; 
     throw; 
    } 
} 

他のすべてのプロパティがうまく更新されます。 LastEditedByのみが更新されません。 CreateメソッドでCreatedByが正しく動作しているのは、データベースに保存されている新しいエンティティなのでです。 ApplicationUserプロパティには、コードで最初に生成されたデータベースに外部キーがあります。

答えて

0

ソリューションがモデルに外部キープロパティを作成することです(そこにデータベースの外部キーがすでにだったが、最初のコードで生成された):

私の提案はこれです。このようにして、LastEditedByユーザがいる場合は、コンストラクタでプロパティを設定できます。

public class HtmlContent : ITextContentItem, ICreateStamp, IEditStamp, IImmutable 
{ 
    // ReSharper disable once UnusedMember.Local 
    private HtmlContent() 
    { 

    } 

    public HtmlContent(string name, string description, string text, DateTime creationDate, 
     DateTime? lastEditDate, ApplicationUser createdBy, ApplicationUser lastEditedBy) 
    { 
     this.Name = name; 
     this.Description = description; 
     this.Text = text; 
     this.CreationDate = creationDate; 
     this.LastEditDate = lastEditDate; 
     this.CreatedBy = createdBy; 

     this.LastEditedBy = lastEditedBy; 
     this.LastEditedById = LastEditedBy?.Id; // Set the id if it isn't null 
    } 

    public HtmlContent(int id, string name, string description, string text, DateTime creationDate, 
     DateTime? lastEditDate, ApplicationUser createdBy, ApplicationUser lastEditedBy) 
     : this(name, description, text, creationDate, lastEditDate, createdBy, lastEditedBy) 
    { 
     this.Id = id; 
    } 

    public int Id { get; private set; } 

    public string Name { get; private set; } 

    public string Description { get; private set; } 

    public string Text { get; private set; } 

    public DateTime CreationDate { get; private set; } 

    public DateTime? LastEditDate { get; private set; } 

    public ApplicationUser CreatedBy { get; private set; } 

    [ForeignKey("LastEditedById")] // Set the foreign key to existing property 
    public ApplicationUser LastEditedBy { get; private set; } 

    // Use a property in the model for saving and not just a property generated by code first in the database 
    public string LastEditedById { get; private set; } 

    internal HtmlContent SetLastEditInfo(DateTime? lastEditDate, ApplicationUser lastEditedBy) 
    { 
     if ((lastEditDate.HasValue && lastEditedBy == null) || 
      (!lastEditDate.HasValue && lastEditedBy != null)) 
     { 
      throw new InvalidOperationException($"{nameof(lastEditDate)} and {nameof(lastEditedBy)} must be used together"); 
     } 

     return new HtmlContent(this.Id, this.Name, this.Description, this.Text, this.CreationDate, lastEditDate, this.CreatedBy, lastEditedBy); 
    } 

    internal HtmlContent UpdateHtmlContent(string name, string description, string text) 
    { 
     return new HtmlContent(this.Id, name, description, text, this.CreationDate, this.LastEditDate, this.CreatedBy, this.LastEditedBy); 
    } 
} 
4

私はこれをやっていることは一度もしていないので間違っているかもしれませんが、あなたのモデルには複数の問題が見えます。

1.データモデルにはプライベートセッターがあり、パラメーターのないコンストラクターはありません。
データモデルはパブリックセッターとゲッターとパラメーターのないコンストラクターを持つ一連のプロパティでなければなりません。これにより、プロパティが設定されたときにEFがナビゲーションプロパティをプロキシすることができます。

2.モデルを作成するコードは、モデル自体の内部にあります。
これは大きな問題ではありませんが、今後は汎用リポジトリなどを使用することはできません。すべてのモデルはにはを知っていなければなりません。これはコードを読み取ることができます。 リポジトリパターンをチェック

3.外部キーが、これは100%では重要ではありませんが、それは最初のデータベースからそれらを選択することなく、関連するエンティティを設定することができますもう一度あなたのナビゲーションプロパティ
のために定義しました。関連するエンティティのIDを設定することができます。

4.あなたは、EFのために、そのプロパティ
休憩追跡を設定するには、新しいエンティティを作成し、また、エンティティのすべての参照整合性を壊すべきではありません。エンティティは、その存続期間の間、同じオブジェクトにする必要があります。これにより、オブジェクトの損失やEFによるトラッキングを行わずにプロパティを変更することができます。

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

    public string Name { get; set; } 

    public string Description { get; set; } 

    public string Text { get; set; } 

    public DateTime CreationDate { get; set; } 

    public DateTime? LastEditDate { get; set; } 

    public int CreatedById { get; set; } 

    public int LastEditedById { get; set; } 

    public ApplicationUser CreatedBy { get; set; } 

    public ApplicationUser LastEditedBy { get; set; } 
} 


public HtmlContentService 
{ 
    public async Task Edit(int id, string name, string description, string text) 
    { 
     try 
     { 
      var content = await this.WithId(id); 

      // no need to detach the object if you arent disposing the context 
      //this.db.Entry(content).State = EntityState.Detached; 

      var currentDate = DateTime.UtcNow; 
      var lastEditedBy = this.userProvider.GetCurrentUser(); 

      // these methods could just be moved into this method 
      this.SetLastEditInfo(content, currentDate, lastEditedBy); 
      this.UpdateHtmlContent(content, name, description, text); 

      this.db.Entry(content).State = EntityState.Modified; 
      await this.db.SaveChangesAsync(); 
     } 
     catch (System.Data.Entity.Validation.DbEntityValidationException ex) 
     { 
      var errors = ex.EntityValidationErrors; 
      throw; 
     } 
    } 

    private void SetLastEditInfo(
     HtmlContent content, 
     DateTime lastEditDate, 
     ApplicationUser lastEditedBy) 
    { 
     if ((lastEditDate.HasValue && lastEditedBy == null) || 
      (!lastEditDate.HasValue && lastEditedBy != null)) 
     { 
      throw new InvalidOperationException(
       $"{nameof(lastEditDate)} and {nameof(lastEditedBy)} must be used together"); 
     } 

     content.LastEditDate = lastEditDate; 
     content.LastEditedBy = lastEditedBy; 
    } 

    private void UpdateHtmlContent(
     HtmlContent content, 
     string name, 
     string description, 
     string text) 
    { 
     content.Name = name; 
     content.Description = description; 
     content.Text = text; 
    } 
} 
+1

理由#4に私の賭けを入れました。 –

+0

まず、反応に感謝します。ほぼ完全なモデルで質問を更新しました。属性のような必要な情報を削除しました。私は 'プライベート'のコンストラクタを持っています。プライベートセットの理由でプロパティを作成した理由は、オブジェクトの外側から値を設定できないためです。オブジェクトは、それがどのように維持され、他の何らかの表面ではなく、どのように維持されるかについての論理を有していなければならない1つのクラスで変更できる場合は、複数のクラスに変更できます。その後、コードの複製がコーナーにあります。私の主体は切り離されているとも言いました。私は追跡をしたくないからです。 –

+0

私は問題の解答を追加します。オブジェクトはオブジェクト自体の外側では「不変」です。正しい方向に私を指摘してくれてありがとう。 –

関連する問題