4

ドメイン モデル レイヤー、リポジトリ レイヤーを構築しました。現在、webApi プロジェクトで使用する DTO レイヤーに取り組んでいます。Update サービス メソッドを実装している最中で、部分的な更新について疑問に思っています。これが私のDTOクラスです:

public class FullPersonDto
    {
        public FullPersonDto()
        {
            Friends = new List<Person>();
        }

        public FullPersonDto(Person person)
        {
            PersonId = person.PersonId;
            DateCreated = person.DateCreated;
            Details = person.Details;
            Friends = new List<Person>();
            foreach (Person friend in person.Friends)
            {
                Friends.Add(new PersonDto(friend));
            }
        }

        [Key]
        public int PersonId { get; set; }

        [Required]
        public virtual DateTime DateCreated { get; set; }

        public virtual string Details { get; set; }

        public List<Person> Friends { get; set; } 

        public Person ToEntity()
        {
            var person = new Person
            {
                PersonId = PersonId,             
                DateCreated = (DateTime) DateCreated,
                Details = Details,
                Friends = new List<Person>()
            };
            foreach (PersonDto friend in Friends)
            {
                person.Friends.Add(friend.ToEntity());
            }
            return person;
        }
    }

私のリポジトリの Update メソッドは次のとおりです。

public Person UpdatePerson(Person person)
        {
            var entry = _db.Entry(person);
            if (entry.State == EntityState.Detached)
            {
                var dbSet = _db.Set<Person>();
                Person attachedPerson = dbSet.Find(person.PersonId);
                if (attachedPerson != null)
                {
                    var attachedEntry = _db.Entry(attachedPerson);
                    attachedEntry.CurrentValues.SetValues(person);  // what if values are null, like ID, or DateCreated?
                }
                else
                {
                    entry.State = EntityState.Modified;
                }

            }
            SaveChanges();
            return person;
        }

私の質問は次のとおりです。webAPI を介して人の詳細を更新するだけでよい場合はどうすればよいですか? PersonDto 全体を構築し、SetValues を使用してオブジェクト全体を更新する慣例ですか、それとも、大量のデータをネットワーク経由で送信する必要がないように、1 つのフィールドのみを更新するように指定できる方法はありますか?私は本当に必要ありません)?

部分的な更新が可能である場合、エンティティ全体を更新するのはいつですか? 5/7 プロパティを更新する必要がある場合でも、SetValues が DTO からフィールドに null を書き込まないように、古いデータを 2/7 に送信して書き直す必要があります。

ここでの助けは素晴らしいでしょう...このことはまったく初めてで、すべてを正しく学ぼうとしています。ありがとうございました。

4

2 に答える 2

2

最適化を行うために同様のアプローチを取りましたが、アタッチ時に null 値で同じ問題に直面しました (null だけでなく、ブール値にも問題があります)。これは私が思いついたものです:

    public static void Update<T>(this DbContext context, IDTO dto)
        where T : class, IEntity
    {
        T TEntity = context.Set<T>().Local.FirstOrDefault(x => x.Id == dto.Id);
        if (TEntity == null)
        {
            TEntity = context.Set<T>().Create();
            TEntity.Id = dto.Id;
            context.Set<T>().Attach(TEntity);
        }
        context.Entry(TEntity).CurrentValues.SetValues(dto);
        var attribute = dto.GetAttribute<EnsureUpdatedAttribute>();
        if (attribute != null)
        {
            foreach (var property in attribute.Properties)
                context.Entry(TEntity).Property(property).IsModified = true;
        }
    }

それが DbContext の拡張メソッドです。インターフェイス IDTO と IEntity は次のとおりです。

public interface IDTO
{
    int Id { get; set; }
}

public interface IEntity
{
    int Id { get; set; }

    Nullable<DateTime> Modified { get; set; }
    Nullable<DateTime> Created { get; set; }
}

カスタムのEnsureUpdatedAttributeを使用して、常に更新する必要があるプロパティに注釈を付けています(追跡されていないnull /デフォルト値に対処するため):

public class EnsureUpdatedAttribute : Attribute
{
    public IEnumerable<string> Properties { get; private set; }

    public EnsureUpdatedAttribute(params string[] properties)
    {
        Properties = properties.AsEnumerable();
    }
}

そして、これは使用例です:

public class Sample : IEntity
{
    public int Id { get; set; }

    public string Name { get; set; }

    public bool Active { get; set; }

    public Nullable<DateTime> Modified { get; set; }
    public Nullable<DateTime> Created { get; set; }
}


[EnsureUpdated("Active")] /// requirement for entity framework change tracking, read about stub entities
public class SampleDTO : IDTO
{
    public int Id { get; set; }

    [Required]
    public string Name { get; set; }

    [JsonIgnore] /// How to exclude property from going on the wire / ignored for serialization
    public bool Active { get; set; }
}

    [HttpPost]
    public HttpResponseMessage SaveSample(SampleDTO dto)
    {
        dto.Active = true;
        _ctx.AddModel<Sample>(dto);
        _ctx.SaveChanges();
        return NoContent();
    }

return NoContent() は、204 (NoContent) を返すための単なる拡張です。

お役に立てれば。

于 2013-03-11T05:20:07.650 に答える
0

必要な部分を更新するためのストアド プロシージャを作成するか (私はこれを行いません)、コンテキストの変更を EF で保存する前にモデルで更新するフィールドを手動で選択することができます。

特定のフィールドを更新する方法の例を次に示します。

public void UpdatePerson(int personId, string details)
{
  var person = new Person() { Id = personId, Details = details };   
  db.Persons.Attach(personId);
  db.Entry(person).Property(x => x.Details).IsModified = true;
  db.SaveChanges();
}

何をしたいかはシナリオによって異なりますが、一般的に言えば、エンティティ全体を更新するために送信しても問題ありません。これは、必要に応じて将来的に変化する可能性のある状況にアプローチする方法です。

于 2013-03-11T03:53:04.413 に答える