Установка значения по умолчанию для Entity при вызове db.SaveChanges () [duplicate]

Еще один способ подумать о unzip или transpose - преобразовать список строк в список столбцов.

pitchers = [('Nolan', 'Ryan'), ('Roger', 'Clements'), ('Schilling','Curt')]
first_names, last_names = zip(*pitchers)
In [45]: first_names
Out[45]: ('Nolan', 'Roger', 'Schilling')
In [46]: last_names
Out[46]: ('Ryan', 'Clements', 'Curt')
39
задан RPM1984 12 October 2010 в 02:04
поделиться

7 ответов

Поскольку у меня есть сервисный уровень, посредник между моими контроллерами (im using ASP.NET MVC) и мой репозиторий, я решил автоматически установить поля здесь.

Кроме того, у моих POCO нет отношений / абстракций, они полностью независимы. Я хотел бы сохранить его таким образом, а не отмечать какие-либо виртуальные свойства или создавать базовые классы.

Итак, я создал интерфейс IAutoGenerateDateFields:

public interface IAutoGenerateDateFields
{
   DateTime LastModified { get;set; }
   DateTime CreatedOn { get;set; }
}

Для любого POCO i хотите автоматически сгенерировать эти поля, я реализую эту интуицию.

Используя пример в моем вопросе:

public class PocoWithDates : IAutoGenerateDateFields
{
   public string PocoName { get; set; }
   public DateTime CreatedOn { get; set; }
   public DateTime LastModified { get; set; }
}

На моем сервисном уровне я теперь проверяю, реализует ли конкретный объект интерфейс:

public void Add(SomePoco poco)
{
   var autoDateFieldsPoco = poco as IAutoGenerateDateFields; // returns null if it's not.

   if (autoDateFieldsPoco != null) // if it implements interface
   {
      autoDateFieldsPoco.LastModified = DateTime.Now;
      autoDateFieldsPoco.CreatedOn = DateTime.Now;
   }

   // ..go on about other persistence work.
}

Я, скорее всего, сломаю этот код в дополнении к методу помощника / расширения позже.

Но я думаю, что это достойное решение для моего сценария , так как я не хочу использовать виртуальные машины в Save (поскольку я использую Unit of Work, Repository и Pure POCO) и не хочу использовать триггеры.

Если у вас есть мысли / предложения, дайте мне знать.

9
ответ дан RPM1984 21 August 2018 в 04:58
поделиться

должен был добавить базовый объект, расширить его из первой частичной базы данных (что не является идеальным)

    public override int SaveChanges()
    {
        AddTimestamps();
        return base.SaveChanges();
    }

    public override async Task<int> SaveChangesAsync()
    {
        AddTimestamps();
        return await base.SaveChangesAsync();
    }

    private void AddTimestamps()
    {
        //var entities = ChangeTracker.Entries().Where(x => x.Entity is BaseEntity && (x.State == EntityState.Added || x.State == EntityState.Modified));

        //ObjectiveContext context = ((IObjectContextAdapter)this).ObjectContext;

        var entities = ChangeTracker.Entries().Where(e => e.Entity is BaseEntity && (e.State == EntityState.Modified || e.State == EntityState.Added)).ToList();

        var currentUsername = !string.IsNullOrEmpty(System.Web.HttpContext.Current?.User?.Identity?.Name)
            ? HttpContext.Current.User.Identity.Name
            : "Anonymous";

        foreach (var entity in entities)
        {
            if (entity.State == EntityState.Added)
            {
                ((BaseEntity)entity.Entity).CREATEDON = DateTime.UtcNow;
                ((BaseEntity)entity.Entity).CREATEDBY = currentUsername;
            }

            ((BaseEntity)entity.Entity).MODIFIEDON = DateTime.UtcNow;
            ((BaseEntity)entity.Entity).MODIFIEDBY = currentUsername;
        }
    }
0
ответ дан cagedwhale 21 August 2018 в 04:58
поделиться

Я также хотел бы предложить последнее решение. Это применимо только к .NET Framework 4, но делает эту задачу тривиальной.

var vs = oceContext.ObjectStateManager.GetObjectStateEntries(EntityState.Modified);
foreach (var v in vs)
{
    dynamic dv = v.Entity;
    dv.DateLastEdit = DateTime.Now;
}
6
ответ дан famousgarkin 21 August 2018 в 04:58
поделиться
  • 1
    Разве это не в основном то же самое, что ответить @ Nick? – RPM1984 26 July 2011 в 00:31
  • 2
    Этот метод не требует базового класса, поэтому цепочка наследования остается неизменной. – chinupson 26 July 2011 в 08:43

У вас есть два варианта:

  • имеют базовый класс для всех классов бизнес-сущностей, который выполняет
    poco.LastModified = DateTime.Now;
    
    в виртуальном .Save() методе, который всем остальным придется называть
  • использовать триггер в базе данных

Я не думаю, что есть какой-либо другой разумно безопасный и простой способ для достижения этого.

1
ответ дан marc_s 21 August 2018 в 04:58
поделиться
  • 1
    Невозможно сделать вариант 1. Сохранить происходит на UnitOfWork (а не на POCO - я должен был упомянуть об этом, извините). Следовательно, я упоминаю «SavingChanges». как возможность. Я действительно не хочу идти по триггерному маршруту (делает отладку кошмаром). Думаю, я предпочел бы вручную устанавливать поля в моем сервисе. – RPM1984 7 October 2010 в 09:52

Для достижения этого мы можем использовать метод partial и переопределить метод SaveChanges.

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Core.Objects;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;


namespace TestDatamodel
{
    public partial class DiagnosisPrescriptionManagementEntities
    {
        public override int SaveChanges()
        {
            ObjectContext context = ((IObjectContextAdapter)this).ObjectContext;

            foreach (ObjectStateEntry entry in
                     (context.ObjectStateManager
                       .GetObjectStateEntries(EntityState.Added | EntityState.Modified)))
            {                    
                if (!entry.IsRelationship)
                {
                    CurrentValueRecord entryValues = entry.CurrentValues;
                    if (entryValues.GetOrdinal("ModifiedBy") > 0)
                    {
                        HttpContext currentContext = HttpContext.Current;
                        string userId = "nazrul";
                        DateTime now = DateTime.Now;

                        if (currContext.User.Identity.IsAuthenticated)
                        {
                            if (currentContext .Session["userId"] != null)
                            {
                                userId = (string)currentContext .Session["userId"];
                            }
                            else
                            {                                    
                                userId = UserAuthentication.GetUserId(currentContext .User.Identity.UserCode);
                            }
                        }

                        if (entry.State == EntityState.Modified)
                        {
                           entryValues.SetString(entryValues.GetOrdinal("ModifiedBy"), userId);
                           entryValues.SetDateTime(entryValues.GetOrdinal("ModifiedDate"), now);
                        }

                        if (entry.State == EntityState.Added)
                        {
                            entryValues.SetString(entryValues.GetOrdinal("CreatedBy"), userId);
                            entryValues.SetDateTime(entryValues.GetOrdinal("CreatedDate"), now);
                        }
                    }
                }
            }

            return base.SaveChanges();
        }
    }
}
0
ответ дан Md. Nazrul Islam 21 August 2018 в 04:58
поделиться

Я знаю, что немного опаздываю на вечеринку, но я просто решил это для проекта, над которым я работаю, и решил поделиться своим решением.

Во-первых, чтобы сделать решение более re-usable, я создал базовый класс со свойствами timestamp:

public class EntityBase
{
    public DateTime? CreatedDate { get; set; }
    public DateTime? LastModifiedDate { get; set; }
}

Затем я переопределил метод SaveChanges в моем DbContext:

public class MyContext : DbContext
{
    public override int SaveChanges()
    {
        ObjectContext context = ((IObjectContextAdapter)this).ObjectContext;

        //Find all Entities that are Added/Modified that inherit from my EntityBase
        IEnumerable<ObjectStateEntry> objectStateEntries =
            from e in context.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified)
            where
                e.IsRelationship == false &&
                e.Entity != null &&
                typeof(EntityBase).IsAssignableFrom(e.Entity.GetType())
            select e;

        var currentTime = DateTime.Now;

        foreach (var entry in objectStateEntries)
        {
            var entityBase = entry.Entity as EntityBase;

            if (entry.State == EntityState.Added)
            {
                entityBase.CreatedDate = currentTime;
            }

            entityBase.LastModifiedDate = currentTime;
        }

        return base.SaveChanges();
    }
}
53
ответ дан Nick 21 August 2018 в 04:58
поделиться
  • 1
    Да, я подумал об этом, но тогда ИМО в POCO больше не «POCOs». поскольку они теперь наследуются от базового класса, единственной целью которого является обслуживание операций с меткой времени (например, проблема с базой данных). – RPM1984 8 June 2011 в 23:34
  • 2
    Если вы не хотите использовать базовый класс для своих POCOs, вы можете использовать entry.CurrentValues ​​[& quot; CreatedDate & quot;] для установки значения. – Rowan 3 June 2013 в 06:04
  • 3
    Очень хорошо. Я немного изменил его, переместив материал EntityBase в интерфейс, и, поскольку я сначала использую базу данных, я добавил ее в шаблон T4, который генерирует пользовательский DBContext. Но очень удобно, спасибо. – Ken Smith 7 June 2013 в 23:56
  • 4
    Не забудьте также отменить SaveChangesAsync. Например. public override Task<int> SaveChangesAsync() { /* do something */ return base.SaveChangesAsync(); } – Shaun Luttin 17 February 2014 в 10:45
  • 5
    Приведенный выше код не работает во всех случаях. Я использую другую логику для получения записей: var entries = ChangeTracker.Entries (); – Echiban 8 March 2014 в 16:09

здесь отредактирована версия предыдущего ответа. Предыдущая версия для меня не работала.

public override int SaveChanges()
    {
        var objectStateEntries = ChangeTracker.Entries()
            .Where(e => e.Entity is TrackedEntityBase && (e.State == EntityState.Modified || e.State == EntityState.Added)).ToList();
        var currentTime = DateTime.UtcNow;
        foreach (var entry in objectStateEntries)
        {
            var entityBase = entry.Entity as TrackedEntityBase;
            if (entityBase == null) continue;
            if (entry.State == EntityState.Added)
            {
                entityBase.CreatedDate = currentTime;
            }
            entityBase.LastModifiedDate = currentTime;
        }

        return base.SaveChanges();
    }
5
ответ дан the_joric 21 August 2018 в 04:58
поделиться
Другие вопросы по тегам:

Похожие вопросы: